Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
IBCHandler
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 10000 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.8.27;
import "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
import "../24-host/IBCStore.sol";
import "../02-client/IBCClient.sol";
import "../03-connection/IBCConnection.sol";
import "../04-channel/IBCChannel.sol";
import "../04-channel/IBCPacket.sol";
import "../../internal/Versioned.sol";
/**
* @dev IBCHandler is a contract that implements [ICS-25](https://github.com/cosmos/ibc/tree/main/spec/core/ics-025-handler-interface).
*/
contract IBCHandler is
Initializable,
UUPSUpgradeable,
IBCStore,
IBCClient,
IBCConnectionImpl,
IBCChannelImpl,
IBCPacketImpl,
Versioned
{
constructor() {
_disableInitializers();
}
function initialize(
address authority
) external initializer {
__IBCHandler_init(authority);
}
function __IBCHandler_init(
address authority
) internal onlyInitializing {
__AccessManaged_init(authority);
__UUPSUpgradeable_init();
commitments[nextClientSequencePath] = bytes32(uint256(1));
commitments[nextChannelSequencePath] = bytes32(uint256(1));
commitments[nextConnectionSequencePath] = bytes32(uint256(1));
}
function _authorizeUpgrade(
address newImplementation
) internal override restricted {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.22;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC-1967 compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC-1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}pragma solidity ^0.8.27;
import
"@openzeppelin-upgradeable/contracts/access/manager/AccessManagedUpgradeable.sol";
import "../02-client/ILightClient.sol";
import "../05-port/IIBCModule.sol";
import "../Types.sol";
library IBCStoreLib {
bytes public constant WASMD_MODULE_STORE_KEY = bytes("wasm");
bytes1 public constant WASMD_CONTRACT_STORE_PREFIX = 0x03;
bytes1 public constant IBC_UNION_COSMWASM_COMMITMENT_PREFIX = 0x00;
uint256 public constant IBC_UNION_EVM_COMMITMENT_SLOT = 0;
}
abstract contract IBCStore is AccessManagedUpgradeable {
// Commitments
// keccak256(IBC-compatible-store-path) => keccak256(IBC-compatible-commitment)
mapping(bytes32 => bytes32) public commitments;
// ClientType -> Address
mapping(string => address) public clientRegistry;
// ClientId -> ClientType
mapping(uint32 => string) public clientTypes;
// ClientId -> Address
mapping(uint32 => address) public clientImpls;
// ConnectionId -> Connection
mapping(uint32 => IBCConnection) public connections;
// ChannelId -> Channel
mapping(uint32 => IBCChannel) public channels;
// ChannelId -> PortId
mapping(uint32 => address) public channelOwner;
// Sequences for identifier
bytes32 constant nextClientSequencePath = keccak256("nextClientSequence");
bytes32 constant nextConnectionSequencePath =
keccak256("nextConnectionSequence");
bytes32 constant nextChannelSequencePath = keccak256("nextChannelSequence");
function getClient(
uint32 clientId
) public view returns (ILightClient) {
return getClientInternal(clientId);
}
function getClientInternal(
uint32 clientId
) internal view returns (ILightClient) {
address clientImpl = clientImpls[clientId];
if (clientImpl == address(0)) {
revert IBCErrors.ErrClientNotFound();
}
return ILightClient(clientImpl);
}
function lookupModuleByChannel(
uint32 channelId
) internal view virtual returns (IIBCModule) {
address module = channelOwner[channelId];
if (module == address(0)) {
revert IBCErrors.ErrModuleNotFound();
}
return IIBCModule(module);
}
function claimChannel(address portId, uint32 channelId) internal {
channelOwner[channelId] = portId;
}
function authenticateChannelOwner(
uint32 channelId
) internal view returns (bool) {
return msg.sender == channelOwner[channelId];
}
function ensureConnectionState(
uint32 connectionId
) internal view returns (uint32) {
IBCConnection storage connection = connections[connectionId];
if (connection.state != IBCConnectionState.Open) {
revert IBCErrors.ErrInvalidConnectionState();
}
return connection.clientId;
}
function ensureChannelState(
uint32 channelId
) internal view returns (IBCChannel storage) {
IBCChannel storage channel = channels[channelId];
if (channel.state != IBCChannelState.Open) {
revert IBCErrors.ErrInvalidChannelState();
}
return channel;
}
}pragma solidity ^0.8.27;
import "./ILightClient.sol";
import "../25-handler/IBCMsgs.sol";
import "../24-host/IBCStore.sol";
import "../24-host/IBCCommitment.sol";
import "../02-client/IIBCClient.sol";
library IBCClientLib {
event RegisterClient(
string indexed clientTypeIndex, string clientType, address clientAddress
);
event CreateClient(
string indexed clientTypeIndex,
string clientType,
uint32 indexed clientId,
string counterpartyChainId
);
event UpdateClient(uint32 indexed clientId, uint64 height);
event Misbehaviour(uint32 indexed clientId);
}
/**
* @dev IBCClient is a router contract that forward calls to clients implementing [ICS-2](https://github.com/cosmos/ibc/tree/main/spec/core/ics-002-client-semantics).
*/
abstract contract IBCClient is IBCStore, IIBCClient {
/**
* @dev registerClient registers a new client type into the client registry
*/
function registerClient(
string calldata clientType,
ILightClient client
) external override restricted {
if (address(clientRegistry[clientType]) != address(0)) {
revert IBCErrors.ErrClientTypeAlreadyExists();
}
clientRegistry[clientType] = address(client);
emit IBCClientLib.RegisterClient(
clientType, clientType, address(client)
);
}
/**
* @dev createClient creates a new client state and populates it with a given consensus state
*/
function createClient(
IBCMsgs.MsgCreateClient calldata msg_
) external override restricted returns (uint32) {
address clientImpl = clientRegistry[msg_.clientType];
if (clientImpl == address(0)) {
revert IBCErrors.ErrClientTypeNotFound();
}
uint32 clientId = generateClientIdentifier();
clientTypes[clientId] = msg_.clientType;
clientImpls[clientId] = clientImpl;
(ConsensusStateUpdate memory update, string memory counterpartyChainId)
= ILightClient(clientImpl).createClient(
msg.sender,
clientId,
msg_.clientStateBytes,
msg_.consensusStateBytes,
msg_.relayer
);
commitments[IBCCommitment.clientStateCommitmentKey(clientId)] =
update.clientStateCommitment;
commitments[IBCCommitment.consensusStateCommitmentKey(
clientId, update.height
)] = update.consensusStateCommitment;
emit IBCClientLib.CreateClient(
msg_.clientType, msg_.clientType, clientId, counterpartyChainId
);
return clientId;
}
/**
* @dev updateClient updates the consensus state and the state root from a provided header
*/
function updateClient(
IBCMsgs.MsgUpdateClient calldata msg_
) external override restricted {
ConsensusStateUpdate memory update = getClientInternal(msg_.clientId)
.updateClient(
msg.sender, msg_.clientId, msg_.clientMessage, msg_.relayer
);
commitments[IBCCommitment.clientStateCommitmentKey(msg_.clientId)] =
update.clientStateCommitment;
commitments[IBCCommitment.consensusStateCommitmentKey(
msg_.clientId, update.height
)] = update.consensusStateCommitment;
emit IBCClientLib.UpdateClient(msg_.clientId, update.height);
}
/**
* @dev forceUpdateClient forcibly updates the consensus state and the state root from a provided header
*/
function forceUpdateClient(
IBCMsgs.MsgForceUpdateClient calldata msg_
) external restricted {
ConsensusStateUpdate memory update = IForceLightClient(
address(getClientInternal(msg_.clientId))
).forceUpdateClient(
msg.sender,
msg_.clientId,
msg_.clientStateBytes,
msg_.consensusStateBytes
);
commitments[IBCCommitment.clientStateCommitmentKey(msg_.clientId)] =
update.clientStateCommitment;
commitments[IBCCommitment.consensusStateCommitmentKey(
msg_.clientId, update.height
)] = update.consensusStateCommitment;
emit IBCClientLib.UpdateClient(msg_.clientId, update.height);
}
/**
* @dev misbehaviour submits a misbehaviour to the client for it to take action if it is correct
*/
function misbehaviour(
IBCMsgs.MsgMisbehaviour calldata msg_
) external override restricted {
getClientInternal(msg_.clientId).misbehaviour(
msg.sender, msg_.clientId, msg_.clientMessage, msg_.relayer
);
emit IBCClientLib.Misbehaviour(msg_.clientId);
}
function generateClientIdentifier() internal returns (uint32) {
uint32 nextClientSequence =
uint32(uint256(commitments[nextClientSequencePath]));
commitments[nextClientSequencePath] =
bytes32(uint256(nextClientSequence + 1));
return nextClientSequence;
}
}pragma solidity ^0.8.27;
import "../24-host/IBCStore.sol";
import "../25-handler/IBCMsgs.sol";
import "../24-host/IBCCommitment.sol";
import "../03-connection/IIBCConnection.sol";
library IBCConnectionLib {
event ConnectionOpenInit(
uint32 indexed connectionId,
uint32 indexed clientId,
uint32 counterpartyClientId
);
event ConnectionOpenTry(
uint32 indexed connectionId,
uint32 indexed clientId,
uint32 counterpartyClientId,
uint32 counterpartyConnectionId
);
event ConnectionOpenAck(
uint32 indexed connectionId,
uint32 indexed clientId,
uint32 counterpartyClientId,
uint32 counterpartyConnectionId
);
event ConnectionOpenConfirm(
uint32 indexed connectionId,
uint32 indexed clientId,
uint32 counterpartyClientId,
uint32 counterpartyConnectionId
);
}
/**
* @dev IBCConnection is a contract that implements [ICS-3](https://github.com/cosmos/ibc/tree/main/spec/core/ics-003-connection-semantics).
*/
abstract contract IBCConnectionImpl is IBCStore, IIBCConnection {
/**
* @dev connectionOpenInit initialises a connection attempt on chain A. The generated connection identifier
* is returned.
*/
function connectionOpenInit(
IBCMsgs.MsgConnectionOpenInit calldata msg_
) external override returns (uint32) {
uint32 connectionId = generateConnectionIdentifier();
IBCConnection storage connection = connections[connectionId];
connection.clientId = msg_.clientId;
connection.state = IBCConnectionState.Init;
connection.counterpartyClientId = msg_.counterpartyClientId;
commitConnection(connectionId, connection);
emit IBCConnectionLib.ConnectionOpenInit(
connectionId, msg_.clientId, msg_.counterpartyClientId
);
return connectionId;
}
function _connectionOpenTry(
IBCMsgs.MsgConnectionOpenTry calldata msg_
) internal returns (uint32) {
uint32 connectionId = generateConnectionIdentifier();
IBCConnection storage connection = connections[connectionId];
connection.clientId = msg_.clientId;
connection.state = IBCConnectionState.TryOpen;
connection.counterpartyClientId = msg_.counterpartyClientId;
connection.counterpartyConnectionId = msg_.counterpartyConnectionId;
commitConnection(connectionId, connection);
emit IBCConnectionLib.ConnectionOpenTry(
connectionId,
msg_.clientId,
msg_.counterpartyClientId,
msg_.counterpartyConnectionId
);
return connectionId;
}
function forceConnectionOpenTry(
IBCMsgs.MsgConnectionOpenTry calldata msg_
) public restricted returns (uint32) {
return _connectionOpenTry(msg_);
}
/**
* @dev connectionOpenTry relays notice of a connection attempt on chain A to chain B (this
* code is executed on chain B).
*/
function connectionOpenTry(
IBCMsgs.MsgConnectionOpenTry calldata msg_
) external override returns (uint32) {
IBCConnection memory expectedConnection = IBCConnection({
state: IBCConnectionState.Init,
clientId: msg_.counterpartyClientId,
counterpartyClientId: msg_.clientId,
counterpartyConnectionId: 0
});
if (
!verifyConnectionState(
msg_.clientId,
msg_.proofHeight,
msg_.proofInit,
msg_.counterpartyConnectionId,
expectedConnection
)
) {
revert IBCErrors.ErrInvalidProof();
}
return _connectionOpenTry(msg_);
}
function _connectionOpenAck(
IBCMsgs.MsgConnectionOpenAck calldata msg_,
IBCConnection storage connection
) internal {
connection.state = IBCConnectionState.Open;
connection.counterpartyConnectionId = msg_.counterpartyConnectionId;
commitConnection(msg_.connectionId, connection);
emit IBCConnectionLib.ConnectionOpenAck(
msg_.connectionId,
connection.clientId,
connection.counterpartyClientId,
connection.counterpartyConnectionId
);
}
function forceConnectionOpenAck(
IBCMsgs.MsgConnectionOpenAck calldata msg_
) public restricted {
_connectionOpenAck(
msg_,
ensureHandshakeState(msg_.connectionId, IBCConnectionState.Init)
);
}
/**
* @dev connectionOpenAck relays acceptance of a connection open attempt from chain B back
* to chain A (this code is executed on chain A).
*/
function connectionOpenAck(
IBCMsgs.MsgConnectionOpenAck calldata msg_
) external override {
IBCConnection storage connection =
ensureHandshakeState(msg_.connectionId, IBCConnectionState.Init);
IBCConnection memory expectedConnection = IBCConnection({
state: IBCConnectionState.TryOpen,
clientId: connection.counterpartyClientId,
counterpartyClientId: connection.clientId,
counterpartyConnectionId: msg_.connectionId
});
if (
!verifyConnectionState(
connection.clientId,
msg_.proofHeight,
msg_.proofTry,
msg_.counterpartyConnectionId,
expectedConnection
)
) {
revert IBCErrors.ErrInvalidProof();
}
_connectionOpenAck(msg_, connection);
}
function _connectionOpenConfirm(
IBCMsgs.MsgConnectionOpenConfirm calldata msg_,
IBCConnection storage connection
) internal {
connection.state = IBCConnectionState.Open;
commitConnection(msg_.connectionId, connection);
emit IBCConnectionLib.ConnectionOpenConfirm(
msg_.connectionId,
connection.clientId,
connection.counterpartyClientId,
connection.counterpartyConnectionId
);
}
function forceConnectionOpenConfirm(
IBCMsgs.MsgConnectionOpenConfirm calldata msg_
) public restricted {
_connectionOpenConfirm(
msg_,
ensureHandshakeState(msg_.connectionId, IBCConnectionState.TryOpen)
);
}
/**
* @dev connectionOpenConfirm confirms opening of a connection on chain A to chain B, after
* which the connection is open on both chains (this code is executed on chain B).
*/
function connectionOpenConfirm(
IBCMsgs.MsgConnectionOpenConfirm calldata msg_
) external override {
IBCConnection storage connection =
ensureHandshakeState(msg_.connectionId, IBCConnectionState.TryOpen);
IBCConnection memory expectedConnection = IBCConnection({
state: IBCConnectionState.Open,
clientId: connection.counterpartyClientId,
counterpartyClientId: connection.clientId,
counterpartyConnectionId: msg_.connectionId
});
if (
!verifyConnectionState(
connection.clientId,
msg_.proofHeight,
msg_.proofAck,
connection.counterpartyConnectionId,
expectedConnection
)
) {
revert IBCErrors.ErrInvalidProof();
}
_connectionOpenConfirm(msg_, connection);
}
function encodeConnection(
IBCConnection memory connection
) internal pure returns (bytes32) {
return keccak256(abi.encode(connection));
}
function encodeConnectionStorage(
IBCConnection storage connection
) internal pure returns (bytes32) {
return keccak256(abi.encode(connection));
}
function commitConnection(
uint32 connectionId,
IBCConnection storage connection
) internal {
commitments[IBCCommitment.connectionCommitmentKey(connectionId)] =
encodeConnectionStorage(connection);
}
function verifyConnectionState(
uint32 clientId,
uint64 height,
bytes calldata proof,
uint32 connectionId,
IBCConnection memory counterpartyConnection
) internal returns (bool) {
return getClientInternal(clientId).verifyMembership(
clientId,
height,
proof,
abi.encodePacked(
IBCCommitment.connectionCommitmentKey(connectionId)
),
abi.encodePacked(encodeConnection(counterpartyConnection))
);
}
function generateConnectionIdentifier() internal returns (uint32) {
uint32 nextConnectionSequence =
uint32(uint256(commitments[nextConnectionSequencePath]));
commitments[nextConnectionSequencePath] =
bytes32(uint256(nextConnectionSequence + 1));
return nextConnectionSequence;
}
function ensureHandshakeState(
uint32 connectionId,
IBCConnectionState state
) internal view returns (IBCConnection storage) {
IBCConnection storage connection = connections[connectionId];
if (connection.state != state) {
revert IBCErrors.ErrInvalidConnectionState();
}
return connection;
}
}pragma solidity ^0.8.27;
import "solady/utils/LibString.sol";
import "../24-host/IBCStore.sol";
import "../25-handler/IBCMsgs.sol";
import "../24-host/IBCCommitment.sol";
import "../04-channel/IIBCChannel.sol";
import "../05-port/IIBCModule.sol";
library IBCChannelLib {
event ChannelOpenInit(
address indexed portId,
uint32 indexed channelId,
bytes counterpartyPortId,
uint32 connectionId,
string indexed versionIndex,
string version
);
event ChannelOpenTry(
address indexed portId,
uint32 indexed channelId,
bytes counterpartyPortId,
uint32 counterpartyChannelId,
uint32 connectionId,
string indexed counterpartyVersionIndex,
string counterpartyVersion
);
event ChannelOpenAck(
address indexed portId,
uint32 indexed channelId,
bytes counterpartyPortId,
uint32 counterpartyChannelId,
uint32 connectionId
);
event ChannelOpenConfirm(
address indexed portId,
uint32 indexed channelId,
bytes counterpartyPortId,
uint32 counterpartyChannelId,
uint32 connectionId
);
event ChannelCloseInit(
address indexed portId,
uint32 indexed channelId,
bytes counterpartyPortId,
uint32 counterpartyChannelId
);
event ChannelCloseConfirm(
address indexed portId,
uint32 indexed channelId,
bytes counterpartyPortId,
uint32 counterpartyChannelId
);
}
/**
* @dev IBCChannelHandshake is a contract that implements [ICS-4](https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics).
*/
abstract contract IBCChannelImpl is IBCStore, IIBCChannel {
using LibString for *;
/**
* @dev channelOpenInit is called by a module to initiate a channel opening handshake with a module on another chain.
*/
function channelOpenInit(
IBCMsgs.MsgChannelOpenInit calldata msg_
) external override returns (uint32) {
ensureConnectionState(msg_.connectionId);
uint32 channelId = generateChannelIdentifier();
IBCChannel storage channel = channels[channelId];
channel.state = IBCChannelState.Init;
channel.connectionId = msg_.connectionId;
channel.version = msg_.version;
channel.counterpartyPortId = msg_.counterpartyPortId;
commitChannel(channelId, channel);
claimChannel(msg_.portId, channelId);
IIBCModule(msg_.portId).onChanOpenInit(
msg.sender, msg_.connectionId, channelId, msg_.version, msg_.relayer
);
emit IBCChannelLib.ChannelOpenInit(
msg_.portId,
channelId,
channel.counterpartyPortId,
msg_.connectionId,
msg_.version,
msg_.version
);
return channelId;
}
function _channelOpenTry(
IBCMsgs.MsgChannelOpenTry calldata msg_
) internal returns (uint32) {
uint32 channelId = generateChannelIdentifier();
channels[channelId] = msg_.channel;
commitChannelCalldata(channelId, msg_.channel);
claimChannel(msg_.portId, channelId);
IIBCModule(msg_.portId).onChanOpenTry(
msg.sender,
msg_.channel.connectionId,
channelId,
msg_.channel.counterpartyChannelId,
msg_.channel.version,
msg_.counterpartyVersion,
msg_.relayer
);
emit IBCChannelLib.ChannelOpenTry(
msg_.portId,
channelId,
msg_.channel.counterpartyPortId,
msg_.channel.counterpartyChannelId,
msg_.channel.connectionId,
msg_.counterpartyVersion,
msg_.counterpartyVersion
);
return channelId;
}
function forceChannelOpenTry(
IBCMsgs.MsgChannelOpenTry calldata msg_
) public restricted returns (uint32) {
if (msg_.channel.state != IBCChannelState.TryOpen) {
revert IBCErrors.ErrInvalidChannelState();
}
return _channelOpenTry(msg_);
}
/**
* @dev channelOpenTry is called by a module to accept the first step of a channel opening handshake initiated by a module on another chain.
*/
function channelOpenTry(
IBCMsgs.MsgChannelOpenTry calldata msg_
) external override returns (uint32) {
if (msg_.channel.state != IBCChannelState.TryOpen) {
revert IBCErrors.ErrInvalidChannelState();
}
uint32 clientId = ensureConnectionState(msg_.channel.connectionId);
IBCChannel memory expectedChannel = IBCChannel({
state: IBCChannelState.Init,
counterpartyChannelId: 0,
connectionId: getCounterpartyConnection(msg_.channel.connectionId),
counterpartyPortId: abi.encodePacked(msg_.portId),
version: msg_.counterpartyVersion
});
if (
!verifyChannelState(
clientId,
msg_.proofHeight,
msg_.proofInit,
msg_.channel.counterpartyChannelId,
expectedChannel
)
) {
revert IBCErrors.ErrInvalidProof();
}
return _channelOpenTry(msg_);
}
function _channelOpenAck(
IBCMsgs.MsgChannelOpenAck calldata msg_,
address portId
) internal {
IBCChannel storage channel = channels[msg_.channelId];
if (channel.state != IBCChannelState.Init) {
revert IBCErrors.ErrInvalidChannelState();
}
channel.state = IBCChannelState.Open;
channel.version = msg_.counterpartyVersion;
channel.counterpartyChannelId = msg_.counterpartyChannelId;
commitChannel(msg_.channelId, channel);
IIBCModule(portId).onChanOpenAck(
msg.sender,
msg_.channelId,
msg_.counterpartyChannelId,
msg_.counterpartyVersion,
msg_.relayer
);
emit IBCChannelLib.ChannelOpenAck(
portId,
msg_.channelId,
channel.counterpartyPortId,
msg_.counterpartyChannelId,
channel.connectionId
);
}
function forceChannelOpenAck(
IBCMsgs.MsgChannelOpenAck calldata msg_
) public restricted {
IBCChannel storage channel = channels[msg_.channelId];
if (channel.state != IBCChannelState.Init) {
revert IBCErrors.ErrInvalidChannelState();
}
_channelOpenAck(msg_, channelOwner[msg_.channelId]);
}
/**
* @dev channelOpenAck is called by the handshake-originating module to acknowledge the acceptance of the initial request by the counterparty module on the other chain.
*/
function channelOpenAck(
IBCMsgs.MsgChannelOpenAck calldata msg_
) external override {
IBCChannel storage channel = channels[msg_.channelId];
if (channel.state != IBCChannelState.Init) {
revert IBCErrors.ErrInvalidChannelState();
}
uint32 clientId = ensureConnectionState(channel.connectionId);
address portId = channelOwner[msg_.channelId];
IBCChannel memory expectedChannel = IBCChannel({
state: IBCChannelState.TryOpen,
counterpartyChannelId: msg_.channelId,
connectionId: getCounterpartyConnection(channel.connectionId),
counterpartyPortId: abi.encodePacked(portId),
version: msg_.counterpartyVersion
});
if (
!verifyChannelState(
clientId,
msg_.proofHeight,
msg_.proofTry,
msg_.counterpartyChannelId,
expectedChannel
)
) {
revert IBCErrors.ErrInvalidProof();
}
_channelOpenAck(msg_, portId);
}
function _channelOpenConfirm(
IBCMsgs.MsgChannelOpenConfirm calldata msg_,
IBCChannel storage channel,
address portId
) internal {
channel.state = IBCChannelState.Open;
commitChannel(msg_.channelId, channel);
IIBCModule(portId).onChanOpenConfirm(
msg.sender, msg_.channelId, msg_.relayer
);
emit IBCChannelLib.ChannelOpenConfirm(
portId,
msg_.channelId,
channel.counterpartyPortId,
channel.counterpartyChannelId,
channel.connectionId
);
}
function forceChannelOpenConfirm(
IBCMsgs.MsgChannelOpenConfirm calldata msg_
) public restricted {
IBCChannel storage channel = channels[msg_.channelId];
if (channel.state != IBCChannelState.TryOpen) {
revert IBCErrors.ErrInvalidChannelState();
}
_channelOpenConfirm(msg_, channel, channelOwner[msg_.channelId]);
}
/**
* @dev channelOpenConfirm is called by the counterparty module to close their end of the channel, since the other end has been closed.
*/
function channelOpenConfirm(
IBCMsgs.MsgChannelOpenConfirm calldata msg_
) external override {
IBCChannel storage channel = channels[msg_.channelId];
if (channel.state != IBCChannelState.TryOpen) {
revert IBCErrors.ErrInvalidChannelState();
}
uint32 clientId = ensureConnectionState(channel.connectionId);
address portId = channelOwner[msg_.channelId];
IBCChannel memory expectedChannel = IBCChannel({
state: IBCChannelState.Open,
counterpartyChannelId: msg_.channelId,
connectionId: getCounterpartyConnection(channel.connectionId),
counterpartyPortId: abi.encodePacked(portId),
version: channel.version
});
if (
!verifyChannelState(
clientId,
msg_.proofHeight,
msg_.proofAck,
channel.counterpartyChannelId,
expectedChannel
)
) {
revert IBCErrors.ErrInvalidProof();
}
_channelOpenConfirm(msg_, channel, portId);
}
/**
* @dev channelCloseInit is called by either module to close their end of the channel. Once closed, channels cannot be reopened.
*/
function channelCloseInit(
IBCMsgs.MsgChannelCloseInit calldata msg_
) external override {
IBCChannel storage channel = channels[msg_.channelId];
if (channel.state != IBCChannelState.Open) {
revert IBCErrors.ErrInvalidChannelState();
}
ensureConnectionState(channel.connectionId);
channel.state = IBCChannelState.Closed;
commitChannel(msg_.channelId, channel);
address portId = channelOwner[msg_.channelId];
IIBCModule(portId).onChanCloseInit(
msg.sender, msg_.channelId, msg_.relayer
);
emit IBCChannelLib.ChannelCloseInit(
portId,
msg_.channelId,
channel.counterpartyPortId,
channel.counterpartyChannelId
);
}
/**
* @dev channelCloseConfirm is called by the counterparty module to close their end of the
* channel, since the other end has been closed.
*/
function channelCloseConfirm(
IBCMsgs.MsgChannelCloseConfirm calldata msg_
) external override {
IBCChannel storage channel = channels[msg_.channelId];
if (channel.state != IBCChannelState.Open) {
revert IBCErrors.ErrInvalidChannelState();
}
uint32 clientId = ensureConnectionState(channel.connectionId);
address portId = channelOwner[msg_.channelId];
IBCChannel memory expectedChannel = IBCChannel({
state: IBCChannelState.Closed,
counterpartyChannelId: msg_.channelId,
connectionId: getCounterpartyConnection(channel.connectionId),
counterpartyPortId: abi.encodePacked(portId),
version: channel.version
});
if (
!verifyChannelState(
clientId,
msg_.proofHeight,
msg_.proofInit,
channel.counterpartyChannelId,
expectedChannel
)
) {
revert IBCErrors.ErrInvalidProof();
}
channel.state = IBCChannelState.Closed;
commitChannel(msg_.channelId, channel);
IIBCModule(portId).onChanCloseConfirm(
msg.sender, msg_.channelId, msg_.relayer
);
emit IBCChannelLib.ChannelCloseConfirm(
portId,
msg_.channelId,
channel.counterpartyPortId,
channel.counterpartyChannelId
);
}
function encodeChannel(
IBCChannel memory channel
) internal pure returns (bytes32) {
return keccak256(abi.encode(channel));
}
function commitChannel(
uint32 channelId,
IBCChannel storage channel
) internal {
commitments[IBCCommitment.channelCommitmentKey(channelId)] =
encodeChannel(channel);
}
function commitChannelCalldata(
uint32 channelId,
IBCChannel calldata channel
) internal {
commitments[IBCCommitment.channelCommitmentKey(channelId)] =
encodeChannelCalldata(channel);
}
function encodeChannelCalldata(
IBCChannel calldata channel
) internal pure returns (bytes32) {
return keccak256(abi.encode(channel));
}
function verifyChannelState(
uint32 clientId,
uint64 height,
bytes calldata proof,
uint32 channelId,
IBCChannel memory channel
) internal returns (bool) {
return getClientInternal(clientId).verifyMembership(
clientId,
height,
proof,
abi.encodePacked(IBCCommitment.channelCommitmentKey(channelId)),
abi.encodePacked(encodeChannel(channel))
);
}
function getCounterpartyConnection(
uint32 connectionId
) internal view returns (uint32) {
return connections[connectionId].counterpartyConnectionId;
}
function generateChannelIdentifier() internal returns (uint32) {
uint32 nextChannelSequence =
uint32(uint256(commitments[nextChannelSequencePath]));
commitments[nextChannelSequencePath] =
bytes32(uint256(nextChannelSequence + 1));
return nextChannelSequence;
}
}pragma solidity ^0.8.27;
import "../24-host/IBCStore.sol";
import "../25-handler/IBCMsgs.sol";
import "../24-host/IBCStore.sol";
import "../24-host/IBCCommitment.sol";
import "../04-channel/IIBCPacket.sol";
import "../05-port/IIBCModule.sol";
import "../Types.sol";
library IBCPacketLib {
bytes32 public constant COMMITMENT_MAGIC =
0x0100000000000000000000000000000000000000000000000000000000000000;
bytes32 public constant COMMITMENT_MAGIC_ACK =
0x0200000000000000000000000000000000000000000000000000000000000000;
bytes32 public constant COMMITMENT_NULL = bytes32(uint256(0));
event PacketSend(
uint32 indexed channelId, bytes32 indexed packetHash, IBCPacket packet
);
event PacketRecv(
uint32 indexed channelId,
bytes32 indexed packetHash,
address indexed maker,
bytes makerMsg
);
event IntentPacketRecv(
uint32 indexed channelId,
bytes32 indexed packetHash,
address indexed maker,
bytes makerMsg
);
event WriteAck(
uint32 indexed channelId,
bytes32 indexed packetHash,
bytes acknowledgement
);
event PacketAck(
uint32 indexed channelId,
bytes32 indexed packetHash,
bytes acknowledgement,
address indexed maker
);
event PacketTimeout(
uint32 indexed channelId,
bytes32 indexed packetHash,
address indexed maker
);
event BatchedPreviouslySent(
uint32 indexed channelId,
bytes32 indexed batchHash,
bytes32 indexed packetHash
);
event BatchedPreviouslyAcked(
uint32 indexed channelId,
bytes32 indexed batchHash,
bytes32 indexed packetHash
);
function commitAcksMemory(
bytes[] memory acks
) internal pure returns (bytes32) {
return mergeAck(keccak256(abi.encode(acks)));
}
function commitAcks(
bytes[] calldata acks
) internal pure returns (bytes32) {
return mergeAck(keccak256(abi.encode(acks)));
}
function commitAck(
bytes memory ack
) internal pure returns (bytes32) {
bytes[] memory acks = new bytes[](1);
acks[0] = ack;
return commitAcksMemory(acks);
}
function commitPacketsMemory(
IBCPacket[] memory packets
) internal pure returns (bytes32) {
return keccak256(abi.encode(packets));
}
function commitPackets(
IBCPacket[] calldata packets
) internal pure returns (bytes32) {
return keccak256(abi.encode(packets));
}
function commitPacket(
IBCPacket memory packet
) internal pure returns (bytes32) {
IBCPacket[] memory packets = new IBCPacket[](1);
packets[0] = packet;
return commitPacketsMemory(packets);
}
function mergeAck(
bytes32 ack
) internal pure returns (bytes32) {
return COMMITMENT_MAGIC
| (
ack
& 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
);
}
}
/**
* @dev IBCPacket is a contract that implements [ICS-4](https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics).
*/
abstract contract IBCPacketImpl is IBCStore, IIBCPacket {
function batchSend(
IBCMsgs.MsgBatchSend calldata msg_
) external override restricted {
uint256 l = msg_.packets.length;
// No reason to batch less than 2 packets as they are already individually committed.
if (l < 2) {
revert IBCErrors.ErrNotEnoughPackets();
}
uint32 channelId = msg_.packets[0].sourceChannelId;
bytes32 batchHash = IBCPacketLib.commitPackets(msg_.packets);
for (uint256 i = 0; i < l; i++) {
IBCPacket calldata packet = msg_.packets[i];
if (i > 0) {
if (packet.sourceChannelId != channelId) {
revert IBCErrors.ErrBatchSameChannelOnly();
}
}
// If the channel mismatch, the commitment will be zero
bytes32 packetHash = IBCPacketLib.commitPacket(packet);
bytes32 commitment =
commitments[IBCCommitment.batchPacketsCommitmentKey(packetHash)];
// Every packet must have been previously sent to be batched
if (commitment != IBCPacketLib.COMMITMENT_MAGIC) {
revert IBCErrors.ErrPacketCommitmentNotFound();
}
emit IBCPacketLib.BatchedPreviouslySent(
channelId, batchHash, packetHash
);
}
commitments[IBCCommitment.batchPacketsCommitmentKey(batchHash)] =
IBCPacketLib.COMMITMENT_MAGIC;
}
function batchAcks(
IBCMsgs.MsgBatchAcks calldata msg_
) external override restricted {
uint256 l = msg_.packets.length;
// No reason to batch less than 2 packets as they are already individually committed.
if (l < 2) {
revert IBCErrors.ErrNotEnoughPackets();
}
uint32 channelId = msg_.packets[0].destinationChannelId;
bytes32 batchHash = IBCPacketLib.commitPackets(msg_.packets);
for (uint256 i = 0; i < l; i++) {
IBCPacket calldata packet = msg_.packets[i];
if (i > 0) {
if (packet.destinationChannelId != channelId) {
revert IBCErrors.ErrBatchSameChannelOnly();
}
}
bytes calldata ack = msg_.acks[i];
// If the channel mismatch, the commitment will be zero.
bytes32 packetHash = IBCPacketLib.commitPacket(packet);
bytes32 commitment = commitments[IBCCommitment
.batchReceiptsCommitmentKey(packetHash)];
// Can't batch an empty ack.
if (
commitment == IBCPacketLib.COMMITMENT_NULL
|| commitment == IBCPacketLib.COMMITMENT_MAGIC
) {
revert IBCErrors.ErrAcknowledgementIsEmpty();
}
// Of course the ack must match.
if (commitment != IBCPacketLib.commitAck(ack)) {
revert IBCErrors.ErrCommittedAckNotPresent();
}
emit IBCPacketLib.BatchedPreviouslyAcked(
channelId, batchHash, packetHash
);
}
commitments[IBCCommitment.batchReceiptsCommitmentKey(
IBCPacketLib.commitPackets(msg_.packets)
)] = IBCPacketLib.commitAcks(msg_.acks);
}
function sendPacket(
uint32 sourceChannelId,
uint64 timeoutHeight,
uint64 timeoutTimestamp,
bytes calldata data
) external override returns (IBCPacket memory) {
// Deprecated timeout height
if (timeoutHeight != 0) {
revert IBCErrors.ErrTimeoutHeightUnsupported();
}
if (timeoutTimestamp == 0) {
revert IBCErrors.ErrTimeoutMustBeSet();
}
if (!authenticateChannelOwner(sourceChannelId)) {
revert IBCErrors.ErrUnauthorized();
}
IBCChannel storage channel = ensureChannelState(sourceChannelId);
IBCPacket memory packet = IBCPacket({
sourceChannelId: sourceChannelId,
destinationChannelId: channel.counterpartyChannelId,
data: data,
timeoutHeight: timeoutHeight,
timeoutTimestamp: timeoutTimestamp
});
bytes32 packetHash = IBCPacketLib.commitPacket(packet);
bytes32 commitmentKey =
IBCCommitment.batchPacketsCommitmentKey(packetHash);
if (commitments[commitmentKey] != IBCPacketLib.COMMITMENT_NULL) {
revert IBCErrors.ErrPacketAlreadyExist();
}
commitments[commitmentKey] = IBCPacketLib.COMMITMENT_MAGIC;
emit IBCPacketLib.PacketSend(sourceChannelId, packetHash, packet);
return packet;
}
function _markPacketAsReceived(
bytes32 commitmentKey
) internal returns (bool) {
bool alreadyReceived =
commitments[commitmentKey] != IBCPacketLib.COMMITMENT_NULL;
if (!alreadyReceived) {
commitments[commitmentKey] = IBCPacketLib.COMMITMENT_MAGIC;
}
return alreadyReceived;
}
function _processReceive(
IBCPacket[] calldata packets,
address maker,
bytes[] calldata makerMsgs,
uint64 proofHeight,
bytes calldata proof,
bool intent
) internal {
uint256 l = packets.length;
if (l == 0) {
revert IBCErrors.ErrNotEnoughPackets();
}
uint32 destinationChannelId = packets[0].destinationChannelId;
IBCChannel storage channel = ensureChannelState(destinationChannelId);
uint32 clientId = ensureConnectionState(channel.connectionId);
if (!intent) {
bytes32 proofCommitmentKey = IBCCommitment.batchPacketsCommitmentKey(
IBCPacketLib.commitPackets(packets)
);
if (
!_verifyCommitment(
clientId,
proofHeight,
proof,
proofCommitmentKey,
IBCPacketLib.COMMITMENT_MAGIC
)
) {
revert IBCErrors.ErrInvalidProof();
}
}
IIBCModule module = lookupModuleByChannel(destinationChannelId);
for (uint256 i = 0; i < l; i++) {
IBCPacket calldata packet = packets[i];
if (packet.destinationChannelId != destinationChannelId) {
revert IBCErrors.ErrBatchSameChannelOnly();
}
// Deprecated timeout height
if (packet.timeoutHeight != 0) {
revert IBCErrors.ErrTimeoutHeightUnsupported();
}
// Check packet timestamp timeout
// For some reason cosmos is using nanos, we try to follow their convention to avoid friction
uint64 currentTimestamp = uint64(block.timestamp * 1e9);
if (currentTimestamp >= packet.timeoutTimestamp) {
revert IBCErrors.ErrTimestampTimeout();
}
bytes32 packetHash = IBCPacketLib.commitPacket(packet);
bytes32 commitmentKey =
IBCCommitment.batchReceiptsCommitmentKey(packetHash);
if (!_markPacketAsReceived(commitmentKey)) {
bytes memory acknowledgement;
bytes calldata makerMsg = makerMsgs[i];
if (intent) {
acknowledgement = module.onRecvIntentPacket(
msg.sender, packet, maker, makerMsg
);
emit IBCPacketLib.IntentPacketRecv(
packet.destinationChannelId, packetHash, maker, makerMsg
);
} else {
acknowledgement =
module.onRecvPacket(msg.sender, packet, maker, makerMsg);
emit IBCPacketLib.PacketRecv(
packet.destinationChannelId, packetHash, maker, makerMsg
);
}
if (acknowledgement.length > 0) {
_writeAcknowledgement(commitmentKey, acknowledgement);
emit IBCPacketLib.WriteAck(
packet.destinationChannelId, packetHash, acknowledgement
);
}
}
}
}
function recvPacket(
IBCMsgs.MsgPacketRecv calldata msg_
) external restricted {
_processReceive(
msg_.packets,
msg_.relayer,
msg_.relayerMsgs,
msg_.proofHeight,
msg_.proof,
false
);
}
function recvIntentPacket(
IBCMsgs.MsgIntentPacketRecv calldata msg_
) external override restricted {
// make an empty calldata value to pass as the proof, this is not read when intent = true
bytes calldata emptyProof;
assembly {
emptyProof.offset := 0
emptyProof.length := 0
}
_processReceive(
msg_.packets,
msg_.marketMaker,
msg_.marketMakerMsgs,
0,
emptyProof,
true
);
}
function _writeAcknowledgement(
bytes32 commitmentKey,
bytes memory acknowledgement
) internal {
bytes32 commitment = commitments[commitmentKey];
if (commitment == IBCPacketLib.COMMITMENT_NULL) {
revert IBCErrors.ErrPacketNotReceived();
}
if (commitment != IBCPacketLib.COMMITMENT_MAGIC) {
revert IBCErrors.ErrAcknowledgementAlreadyExists();
}
commitments[commitmentKey] = IBCPacketLib.commitAck(acknowledgement);
}
function writeAcknowledgement(
IBCPacket calldata packet,
bytes memory acknowledgement
) external override {
if (acknowledgement.length == 0) {
revert IBCErrors.ErrAcknowledgementIsEmpty();
}
if (!authenticateChannelOwner(packet.destinationChannelId)) {
revert IBCErrors.ErrUnauthorized();
}
ensureChannelState(packet.destinationChannelId);
bytes32 packetHash = IBCPacketLib.commitPacket(packet);
bytes32 commitmentKey =
IBCCommitment.batchReceiptsCommitmentKey(packetHash);
_writeAcknowledgement(commitmentKey, acknowledgement);
emit IBCPacketLib.WriteAck(
packet.destinationChannelId, packetHash, acknowledgement
);
}
function acknowledgePacket(
IBCMsgs.MsgPacketAcknowledgement calldata msg_
) external override restricted {
uint256 l = msg_.packets.length;
if (l == 0) {
revert IBCErrors.ErrNotEnoughPackets();
}
uint32 sourceChannelId = msg_.packets[0].sourceChannelId;
IBCChannel storage channel = ensureChannelState(sourceChannelId);
uint32 clientId = ensureConnectionState(channel.connectionId);
bytes32 commitmentKey = IBCCommitment.batchReceiptsCommitmentKey(
IBCPacketLib.commitPackets(msg_.packets)
);
bytes32 commitmentValue = IBCPacketLib.commitAcks(msg_.acknowledgements);
if (
!_verifyCommitment(
clientId,
msg_.proofHeight,
msg_.proof,
commitmentKey,
commitmentValue
)
) {
revert IBCErrors.ErrInvalidProof();
}
IIBCModule module = lookupModuleByChannel(sourceChannelId);
for (uint256 i = 0; i < l; i++) {
IBCPacket calldata packet = msg_.packets[i];
if (packet.sourceChannelId != sourceChannelId) {
revert IBCErrors.ErrBatchSameChannelOnly();
}
_markPacketAsAcknowledged(packet);
bytes calldata acknowledgement = msg_.acknowledgements[i];
module.onAcknowledgementPacket(
msg.sender, packet, acknowledgement, msg_.relayer
);
emit IBCPacketLib.PacketAck(
sourceChannelId,
IBCPacketLib.commitPacket(packet),
acknowledgement,
msg_.relayer
);
}
}
function timeoutPacket(
IBCMsgs.MsgPacketTimeout calldata msg_
) external override restricted {
IBCPacket calldata packet = msg_.packet;
uint32 sourceChannelId = packet.sourceChannelId;
IBCChannel storage channel = ensureChannelState(sourceChannelId);
uint32 clientId = ensureConnectionState(channel.connectionId);
ILightClient client = getClientInternal(clientId);
uint64 proofTimestamp =
client.getTimestampAtHeight(clientId, msg_.proofHeight);
if (proofTimestamp == 0) {
revert IBCErrors.ErrLatestTimestampNotFound();
}
bytes32 packetHash = IBCPacketLib.commitPacket(packet);
bytes32 commitmentKey =
IBCCommitment.batchReceiptsCommitmentKey(packetHash);
if (
!_verifyAbsentCommitment(
clientId, msg_.proofHeight, msg_.proof, commitmentKey
)
) {
revert IBCErrors.ErrInvalidProof();
}
IIBCModule module = lookupModuleByChannel(sourceChannelId);
_markPacketAsAcknowledged(packet);
if (packet.timeoutTimestamp == 0) {
revert IBCErrors.ErrTimeoutMustBeSet();
}
if (packet.timeoutTimestamp > proofTimestamp) {
revert IBCErrors.ErrTimeoutTimestampNotReached();
}
module.onTimeoutPacket(msg.sender, packet, msg_.relayer);
emit IBCPacketLib.PacketTimeout(
sourceChannelId, packetHash, msg_.relayer
);
}
function _verifyCommitment(
uint32 clientId,
uint64 height,
bytes calldata proof,
bytes32 path,
bytes32 commitment
) internal virtual returns (bool) {
return getClientInternal(clientId).verifyMembership(
clientId,
height,
proof,
abi.encodePacked(path),
abi.encodePacked(commitment)
);
}
function _verifyAbsentCommitment(
uint32 clientId,
uint64 height,
bytes calldata proof,
bytes32 path
) internal virtual returns (bool) {
return getClientInternal(clientId).verifyNonMembership(
clientId, height, proof, abi.encodePacked(path)
);
}
function _markPacketAsAcknowledged(
IBCPacket calldata packet
) internal {
bytes32 commitmentKey = IBCCommitment.batchPacketsCommitmentKey(
IBCPacketLib.commitPacket(packet)
);
bytes32 commitment = commitments[commitmentKey];
if (commitment == IBCPacketLib.COMMITMENT_MAGIC_ACK) {
revert IBCErrors.ErrPacketAlreadyAcknowledged();
}
if (commitment != IBCPacketLib.COMMITMENT_MAGIC) {
revert IBCErrors.ErrPacketCommitmentNotFound();
}
commitments[commitmentKey] = IBCPacketLib.COMMITMENT_MAGIC_ACK;
}
}pragma solidity ^0.8.27;
library VersionedLib {
function gitRev() internal pure returns (string memory) {
return "7113f2661025803021f819add09995fce2f58abf";
}
}
abstract contract Versioned {
function gitRev() public pure returns (string memory) {
return VersionedLib.gitRev();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.22;
import {IBeacon} from "../beacon/IBeacon.sol";
import {IERC1967} from "../../interfaces/IERC1967.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This library provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
*/
library ERC1967Utils {
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the ERC-1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit IERC1967.Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the ERC-1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit IERC1967.AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the ERC-1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit IERC1967.BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/manager/AccessManaged.sol)
pragma solidity ^0.8.20;
import {IAuthority} from "@openzeppelin/contracts/access/manager/IAuthority.sol";
import {AuthorityUtils} from "@openzeppelin/contracts/access/manager/AuthorityUtils.sol";
import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev This contract module makes available a {restricted} modifier. Functions decorated with this modifier will be
* permissioned according to an "authority": a contract like {AccessManager} that follows the {IAuthority} interface,
* implementing a policy that allows certain callers to access certain functions.
*
* IMPORTANT: The `restricted` modifier should never be used on `internal` functions, judiciously used in `public`
* functions, and ideally only used in `external` functions. See {restricted}.
*/
abstract contract AccessManagedUpgradeable is Initializable, ContextUpgradeable, IAccessManaged {
/// @custom:storage-location erc7201:openzeppelin.storage.AccessManaged
struct AccessManagedStorage {
address _authority;
bool _consumingSchedule;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessManaged")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessManagedStorageLocation = 0xf3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a00;
function _getAccessManagedStorage() private pure returns (AccessManagedStorage storage $) {
assembly {
$.slot := AccessManagedStorageLocation
}
}
/**
* @dev Initializes the contract connected to an initial authority.
*/
function __AccessManaged_init(address initialAuthority) internal onlyInitializing {
__AccessManaged_init_unchained(initialAuthority);
}
function __AccessManaged_init_unchained(address initialAuthority) internal onlyInitializing {
_setAuthority(initialAuthority);
}
/**
* @dev Restricts access to a function as defined by the connected Authority for this contract and the
* caller and selector of the function that entered the contract.
*
* [IMPORTANT]
* ====
* In general, this modifier should only be used on `external` functions. It is okay to use it on `public`
* functions that are used as external entry points and are not called internally. Unless you know what you're
* doing, it should never be used on `internal` functions. Failure to follow these rules can have critical security
* implications! This is because the permissions are determined by the function that entered the contract, i.e. the
* function at the bottom of the call stack, and not the function where the modifier is visible in the source code.
* ====
*
* [WARNING]
* ====
* Avoid adding this modifier to the https://docs.soliditylang.org/en/v0.8.20/contracts.html#receive-ether-function[`receive()`]
* function or the https://docs.soliditylang.org/en/v0.8.20/contracts.html#fallback-function[`fallback()`]. These
* functions are the only execution paths where a function selector cannot be unambiguously determined from the calldata
* since the selector defaults to `0x00000000` in the `receive()` function and similarly in the `fallback()` function
* if no calldata is provided. (See {_checkCanCall}).
*
* The `receive()` function will always panic whereas the `fallback()` may panic depending on the calldata length.
* ====
*/
modifier restricted() {
_checkCanCall(_msgSender(), _msgData());
_;
}
/// @inheritdoc IAccessManaged
function authority() public view virtual returns (address) {
AccessManagedStorage storage $ = _getAccessManagedStorage();
return $._authority;
}
/// @inheritdoc IAccessManaged
function setAuthority(address newAuthority) public virtual {
address caller = _msgSender();
if (caller != authority()) {
revert AccessManagedUnauthorized(caller);
}
if (newAuthority.code.length == 0) {
revert AccessManagedInvalidAuthority(newAuthority);
}
_setAuthority(newAuthority);
}
/// @inheritdoc IAccessManaged
function isConsumingScheduledOp() public view returns (bytes4) {
AccessManagedStorage storage $ = _getAccessManagedStorage();
return $._consumingSchedule ? this.isConsumingScheduledOp.selector : bytes4(0);
}
/**
* @dev Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the
* permissions set by the current authority.
*/
function _setAuthority(address newAuthority) internal virtual {
AccessManagedStorage storage $ = _getAccessManagedStorage();
$._authority = newAuthority;
emit AuthorityUpdated(newAuthority);
}
/**
* @dev Reverts if the caller is not allowed to call the function identified by a selector. Panics if the calldata
* is less than 4 bytes long.
*/
function _checkCanCall(address caller, bytes calldata data) internal virtual {
AccessManagedStorage storage $ = _getAccessManagedStorage();
(bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay(
authority(),
caller,
address(this),
bytes4(data[0:4])
);
if (!immediate) {
if (delay > 0) {
$._consumingSchedule = true;
IAccessManager(authority()).consumeScheduledOp(caller, data);
$._consumingSchedule = false;
} else {
revert AccessManagedUnauthorized(caller);
}
}
}
}pragma solidity ^0.8.27;
import "../Types.sol";
struct ConsensusStateUpdate {
bytes32 clientStateCommitment;
bytes32 consensusStateCommitment;
uint64 height;
}
event CreateLensClient(
uint32 indexed clientId,
uint32 indexed l1ClientId,
uint32 indexed l2ClientId,
string l2ChainId
);
/**
* @dev This defines an interface for Light Client contract can be integrated with ibc-solidity.
* You can register the Light Client contract that implements this through `registerClient` on IBCHandler.
*/
interface ILightClient {
/**
* @dev createClient creates a new client with the given state.
* If succeeded, it returns a commitment for the initial state.
*/
function createClient(
address caller,
uint32 clientId,
bytes calldata clientStateBytes,
bytes calldata consensusStateBytes,
address relayer
)
external
returns (
ConsensusStateUpdate memory update,
string memory counterpartyChainId
);
/**
* @dev getTimestampAtHeight returns the timestamp of the consensus state at the given height.
*/
function getTimestampAtHeight(
uint32 clientId,
uint64 height
) external view returns (uint64);
/**
* @dev getLatestHeight returns the latest height of the client state corresponding to `clientId`.
*/
function getLatestHeight(
uint32 clientId
) external view returns (uint64 height);
/**
* @dev updateClient updates the client corresponding to `clientId`.
* If succeeded, it returns a commitment for the updated state.
* If there are no updates for consensus state, this function should returns an empty array as `updates`.
*
* NOTE: updateClient is intended to perform the followings:
* 1. verify a given client message(e.g. header)
* 2. check misbehaviour such like duplicate block height
* 3. if misbehaviour is found, update state accordingly and return
* 4. update state(s) with the client message
* 5. persist the state(s) on the host
*/
function updateClient(
address caller,
uint32 clientId,
bytes calldata clientMessageBytes,
address relayer
) external returns (ConsensusStateUpdate memory update);
/**
* @dev misbehaviour is used for submitting a misbehaviour to `clientId`.
* If succeeded, the client should freeze itself to prevent getting further updates.
*/
function misbehaviour(
address caller,
uint32 clientId,
bytes calldata clientMessageBytes,
address relayer
) external;
/**
* @dev verifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height.
* The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
*/
function verifyMembership(
uint32 clientId,
uint64 height,
bytes calldata proof,
bytes calldata path,
bytes calldata value
) external returns (bool);
/**
* @dev verifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height.
* The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
*/
function verifyNonMembership(
uint32 clientId,
uint64 height,
bytes calldata proof,
bytes calldata path
) external returns (bool);
/**
* @dev getClientState returns the clientState corresponding to `clientId`.
*/
function getClientState(
uint32 clientId
) external view returns (bytes memory);
/**
* @dev getConsensusState returns the consensusState corresponding to `clientId` and `height`.
*/
function getConsensusState(
uint32 clientId,
uint64 height
) external view returns (bytes memory);
/**
* @dev isFrozen returns whether the `clientId` is frozen or not.
*/
function isFrozen(
uint32 clientId
) external view returns (bool);
}
interface IForceLightClient {
function forceUpdateClient(
address caller,
uint32 clientId,
bytes calldata clientStateBytes,
bytes calldata consensusStateBytes
) external returns (ConsensusStateUpdate memory update);
}pragma solidity ^0.8.27;
import "../Types.sol";
interface IIBCModuleRecv {
function onRecvPacket(
address caller,
IBCPacket calldata packet,
address relayer,
bytes calldata relayerMsg
) external returns (bytes memory);
function onRecvIntentPacket(
address caller,
IBCPacket calldata packet,
address marketMaker,
bytes calldata marketMakerMsg
) external returns (bytes memory);
}
// IIBCModule defines an interface that implements all the callbacks
// that modules must define as specified in ICS-26
// https://github.com/cosmos/ibc/blob/2921c5cec7b18e4ef77677e16a6b693051ae3b35/spec/core/ics-026-routing-module/README.md
interface IIBCModule is IIBCModuleRecv {
function onChanOpenInit(
address caller,
uint32 connectionId,
uint32 channelId,
string calldata version,
address relayer
) external;
function onChanOpenTry(
address caller,
uint32 connectionId,
uint32 channelId,
uint32 counterpartyChannelId,
string calldata version,
string calldata counterpartyVersion,
address relayer
) external;
function onChanOpenAck(
address caller,
uint32 channelId,
uint32 counterpartyChannelId,
string calldata counterpartyVersion,
address relayer
) external;
function onChanOpenConfirm(
address caller,
uint32 channelId,
address relayer
) external;
function onChanCloseInit(
address caller,
uint32 channelId,
address relayer
) external;
function onChanCloseConfirm(
address caller,
uint32 channelId,
address relayer
) external;
function onAcknowledgementPacket(
address caller,
IBCPacket calldata packet,
bytes calldata acknowledgement,
address relayer
) external;
function onTimeoutPacket(
address caller,
IBCPacket calldata,
address relayer
) external;
}pragma solidity ^0.8.27;
enum IBCConnectionState {
Unspecified,
Init,
TryOpen,
Open
}
struct IBCConnection {
IBCConnectionState state;
uint32 clientId;
uint32 counterpartyClientId;
uint32 counterpartyConnectionId;
}
enum IBCChannelState {
Unspecified,
Init,
TryOpen,
Open,
Closed
}
struct IBCChannel {
IBCChannelState state;
uint32 connectionId;
uint32 counterpartyChannelId;
bytes counterpartyPortId;
string version;
}
struct IBCPacket {
uint32 sourceChannelId;
uint32 destinationChannelId;
bytes data;
uint64 timeoutHeight;
uint64 timeoutTimestamp;
}
library IBCErrors {
error ErrClientTypeAlreadyExists();
error ErrClientTypeNotFound();
error ErrInvalidProof();
error ErrInvalidConnectionState();
error ErrInvalidChannelState();
error ErrUnauthorized();
error ErrLatestTimestampNotFound();
error ErrTimeoutMustBeSet();
error ErrTimeoutHeightUnsupported();
error ErrHeightTimeout();
error ErrTimestampTimeout();
error ErrAcknowledgementIsEmpty();
error ErrPacketNotReceived();
error ErrAcknowledgementAlreadyExists();
error ErrPacketCommitmentNotFound();
error ErrPacketAlreadyAcknowledged();
error ErrTimeoutHeightNotReached();
error ErrTimeoutTimestampNotReached();
error ErrNotEnoughPackets();
error ErrBatchSameChannelOnly();
error ErrCommittedAckNotPresent();
error ErrClientNotFound();
error ErrModuleNotFound();
error ErrPacketAlreadyExist();
}pragma solidity ^0.8.27;
import "../Types.sol";
/**
* @dev IBCMsgs provides datagram types in [ICS-26](https://github.com/cosmos/ibc/tree/main/spec/core/ics-026-routing-module#datagram-handlers-write)
*/
library IBCMsgs {
struct MsgCreateClient {
string clientType;
bytes clientStateBytes;
bytes consensusStateBytes;
address relayer;
}
struct MsgUpdateClient {
uint32 clientId;
bytes clientMessage;
address relayer;
}
struct MsgForceUpdateClient {
uint32 clientId;
bytes clientStateBytes;
bytes consensusStateBytes;
}
struct MsgConnectionOpenInit {
uint32 clientId;
uint32 counterpartyClientId;
}
struct MsgConnectionOpenTry {
uint32 counterpartyClientId;
uint32 counterpartyConnectionId;
uint32 clientId;
bytes proofInit;
uint64 proofHeight;
}
struct MsgConnectionOpenAck {
uint32 connectionId;
uint32 counterpartyConnectionId;
bytes proofTry;
uint64 proofHeight;
}
struct MsgConnectionOpenConfirm {
uint32 connectionId;
bytes proofAck;
uint64 proofHeight;
}
struct MsgChannelOpenInit {
address portId;
bytes counterpartyPortId;
uint32 connectionId;
string version;
address relayer;
}
struct MsgChannelOpenTry {
address portId;
IBCChannel channel;
string counterpartyVersion;
bytes proofInit;
uint64 proofHeight;
address relayer;
}
struct MsgChannelOpenAck {
uint32 channelId;
string counterpartyVersion;
uint32 counterpartyChannelId;
bytes proofTry;
uint64 proofHeight;
address relayer;
}
struct MsgChannelOpenConfirm {
uint32 channelId;
bytes proofAck;
uint64 proofHeight;
address relayer;
}
struct MsgChannelCloseInit {
uint32 channelId;
address relayer;
}
struct MsgChannelCloseConfirm {
uint32 channelId;
bytes proofInit;
uint64 proofHeight;
address relayer;
}
struct MsgPacketRecv {
IBCPacket[] packets;
bytes[] relayerMsgs;
address relayer;
bytes proof;
uint64 proofHeight;
}
struct MsgPacketAcknowledgement {
IBCPacket[] packets;
bytes[] acknowledgements;
bytes proof;
uint64 proofHeight;
address relayer;
}
struct MsgPacketTimeout {
IBCPacket packet;
bytes proof;
uint64 proofHeight;
address relayer;
}
struct MsgIntentPacketRecv {
IBCPacket[] packets;
bytes[] marketMakerMsgs;
address marketMaker;
}
struct MsgBatchSend {
IBCPacket[] packets;
}
struct MsgBatchAcks {
IBCPacket[] packets;
bytes[] acks;
}
struct MsgMisbehaviour {
uint32 clientId;
bytes clientMessage;
address relayer;
}
}pragma solidity ^0.8.27;
library IBCCommitment {
uint256 public constant CLIENT_STATE = 0x00;
uint256 public constant CONSENSUS_STATE = 0x01;
uint256 public constant CONNECTIONS = 0x02;
uint256 public constant CHANNELS = 0x03;
uint256 public constant PACKETS = 0x04;
uint256 public constant PACKET_ACKS = 0x05;
function clientStatePath(
uint32 clientId
) internal pure returns (bytes memory) {
return abi.encode(CLIENT_STATE, clientId);
}
function consensusStatePath(
uint32 clientId,
uint64 height
) internal pure returns (bytes memory) {
return abi.encode(CONSENSUS_STATE, clientId, height);
}
function connectionPath(
uint32 connectionId
) internal pure returns (bytes memory) {
return abi.encode(CONNECTIONS, connectionId);
}
function channelPath(
uint32 channelId
) internal pure returns (bytes memory) {
return abi.encode(CHANNELS, channelId);
}
function batchPacketsCommitmentPath(
bytes32 batchHash
) internal pure returns (bytes memory) {
return abi.encode(PACKETS, batchHash);
}
function batchReceiptsCommitmentPath(
bytes32 batchHash
) internal pure returns (bytes memory) {
return abi.encode(PACKET_ACKS, batchHash);
}
// Key generators for Commitment mapping
function clientStateCommitmentKey(
uint32 clientId
) internal pure returns (bytes32) {
return keccak256(clientStatePath(clientId));
}
function consensusStateCommitmentKey(
uint32 clientId,
uint64 height
) internal pure returns (bytes32) {
return keccak256(consensusStatePath(clientId, height));
}
function connectionCommitmentKey(
uint32 connectionId
) internal pure returns (bytes32) {
return keccak256(connectionPath(connectionId));
}
function channelCommitmentKey(
uint32 channelId
) internal pure returns (bytes32) {
return keccak256(channelPath(channelId));
}
function batchPacketsCommitmentKey(
bytes32 batchHash
) internal pure returns (bytes32) {
return keccak256(batchPacketsCommitmentPath(batchHash));
}
function batchReceiptsCommitmentKey(
bytes32 batchHash
) internal pure returns (bytes32) {
return keccak256(batchReceiptsCommitmentPath(batchHash));
}
}pragma solidity ^0.8.27;
import "./ILightClient.sol";
import "../25-handler/IBCMsgs.sol";
interface IIBCClient {
/**
* @dev registerClient registers a new client type into the client registry
*/
function registerClient(
string calldata clientType,
ILightClient client
) external;
/**
* @dev createClient creates a new client state and populates it with a given consensus state
*/
function createClient(
IBCMsgs.MsgCreateClient calldata msg_
) external returns (uint32 clientId);
/**
* @dev updateClient updates the consensus state and the state root from a provided header
*/
function updateClient(
IBCMsgs.MsgUpdateClient calldata msg_
) external;
/**
* @dev forceUpdateClient forcibly updates the client and consensus state
*/
function forceUpdateClient(
IBCMsgs.MsgForceUpdateClient calldata msg_
) external;
/**
* @dev misbehaviour submits a misbehaviour to the client for it to take action if it is correct
*/
function misbehaviour(
IBCMsgs.MsgMisbehaviour calldata msg_
) external;
}pragma solidity ^0.8.27;
import "../25-handler/IBCMsgs.sol";
interface IIBCConnection {
/* Handshake functions */
/**
* @dev connectionOpenInit initialises a connection attempt on chain A. The generated connection identifier
* is returned.
*/
function connectionOpenInit(
IBCMsgs.MsgConnectionOpenInit calldata msg_
) external returns (uint32);
/**
* @dev connectionOpenTry relays notice of a connection attempt on chain A to chain B (this
* code is executed on chain B).
*/
function connectionOpenTry(
IBCMsgs.MsgConnectionOpenTry calldata msg_
) external returns (uint32);
/**
* @dev connectionOpenAck relays acceptance of a connection open attempt from chain B back
* to chain A (this code is executed on chain A).
*/
function connectionOpenAck(
IBCMsgs.MsgConnectionOpenAck calldata msg_
) external;
/**
* @dev connectionOpenConfirm confirms opening of a connection on chain A to chain B, after
* which the connection is open on both chains (this code is executed on chain B).
*/
function connectionOpenConfirm(
IBCMsgs.MsgConnectionOpenConfirm calldata msg_
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {LibBytes} from "./LibBytes.sol";
/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
///
/// @dev Note:
/// For performance and bytecode compactness, most of the string operations are restricted to
/// byte strings (7-bit ASCII), except where otherwise specified.
/// Usage of byte string operations on charsets with runes spanning two or more bytes
/// can lead to undefined behavior.
library LibString {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated string storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native string storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct StringStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The length of the output is too small to contain all the hex digits.
error HexLengthInsufficient();
/// @dev The length of the string is more than 32 bytes.
error TooBigForSmallString();
/// @dev The input string must be a 7-bit ASCII.
error StringNot7BitASCII();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the string.
uint256 internal constant NOT_FOUND = type(uint256).max;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'.
uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000;
/// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000;
/// @dev Lookup for '0123456789'.
uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000;
/// @dev Lookup for '0123456789abcdefABCDEF'.
uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000;
/// @dev Lookup for '01234567'.
uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'.
uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00;
/// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'.
uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000;
/// @dev Lookup for ' \t\n\r\x0b\x0c'.
uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRING STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the string storage `$` to `s`.
function set(StringStorage storage $, string memory s) internal {
LibBytes.set(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to `s`.
function setCalldata(StringStorage storage $, string calldata s) internal {
LibBytes.setCalldata(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to the empty string.
function clear(StringStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty string "".
function isEmpty(StringStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(StringStorage storage $) internal view returns (uint256) {
return LibBytes.length(bytesStorage($));
}
/// @dev Returns the value stored in `$`.
function get(StringStorage storage $) internal view returns (string memory) {
return string(LibBytes.get(bytesStorage($)));
}
/// @dev Helper to cast `$` to a `BytesStorage`.
function bytesStorage(StringStorage storage $)
internal
pure
returns (LibBytes.BytesStorage storage casted)
{
/// @solidity memory-safe-assembly
assembly {
casted.slot := $.slot
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the base 10 decimal representation of `value`.
function toString(uint256 value) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end of the memory to calculate the length later.
let w := not(0) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
result := add(result, w) // `sub(result, 1)`.
// Store the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(result, add(48, mod(temp, 10)))
temp := div(temp, 10) // Keep dividing `temp` until zero.
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the base 10 decimal representation of `value`.
function toString(int256 value) internal pure returns (string memory result) {
if (value >= 0) return toString(uint256(value));
unchecked {
result = toString(~uint256(value) + 1);
}
/// @solidity memory-safe-assembly
assembly {
// We still have some spare memory space on the left,
// as we have allocated 3 words (96 bytes) for up to 78 digits.
let n := mload(result) // Load the string length.
mstore(result, 0x2d) // Store the '-' character.
result := sub(result, 1) // Move back the string pointer by a byte.
mstore(result, add(n, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HEXADECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2 + 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexString(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value, byteCount);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexStringNoPrefix(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes
// for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
// We add 0x20 to the total and round down to a multiple of 0x20.
// (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f)))
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(result, add(byteCount, byteCount))
let w := not(1) // Tsk.
let temp := value
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for {} 1 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(result, start)) { break }
}
if temp {
mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
revert(0x1c, 0x04)
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2 + 2` bytes.
function toHexString(uint256 value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x".
/// The output excludes leading "0" from the `toHexString` output.
/// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
function toMinimalHexString(uint256 value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := add(mload(result), 2) // Compute the length.
mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero.
result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output excludes leading "0" from the `toHexStringNoPrefix` output.
/// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
function toMinimalHexStringNoPrefix(uint256 value)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := mload(result) // Get the length.
result := add(result, o) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2` bytes.
function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x40 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
let w := not(1) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
/// and the alphabets are capitalized conditionally according to
/// https://eips.ethereum.org/EIPS/eip-55
function toHexStringChecksummed(address value) internal pure returns (string memory result) {
result = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(result, 0x22)
let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
let t := shl(240, 136) // `0b10001000 << 240`
for { let i := 0 } 1 {} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i := add(i, 1)
if eq(i, 20) { break }
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o := add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
function toHexString(address value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(address value) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Allocate memory.
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x28 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
mstore(0x40, add(result, 0x80))
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
result := add(result, 2)
mstore(result, 40) // Store the length.
let o := add(result, 0x20)
mstore(add(o, 40), 0) // Zeroize the slot after the string.
value := shl(96, value)
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let i := 0 } 1 {} {
let p := add(o, add(i, i))
let temp := byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i := add(i, 1)
if eq(i, 20) { break }
}
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexString(bytes memory raw) internal pure returns (string memory result) {
result = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(raw)
result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(result, add(n, n)) // Store the length of the output.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
let o := add(result, 0x20)
let end := add(raw, n)
for {} iszero(eq(raw, end)) {} {
raw := add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o := add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RUNE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the number of UTF characters in the string.
function runeCount(string memory s) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
mstore(0x00, div(not(0), 255))
mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
let o := add(s, 0x20)
let end := add(o, mload(s))
for { result := 1 } 1 { result := add(result, 1) } {
o := add(o, byte(0, mload(shr(250, mload(o)))))
if iszero(lt(o, end)) { break }
}
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string.
/// (i.e. all characters codes are in [0..127])
function is7BitASCII(string memory s) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
let mask := shl(7, div(not(0), 255))
let n := mload(s)
if n {
let o := add(s, 0x20)
let end := add(o, n)
let last := mload(end)
mstore(end, 0)
for {} 1 {} {
if and(mask, mload(o)) {
result := 0
break
}
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(end, last)
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string,
/// AND all characters are in the `allowed` lookup.
/// Note: If `s` is empty, returns true regardless of `allowed`.
function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
if mload(s) {
let allowed_ := shr(128, shl(128, allowed))
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := and(result, shr(byte(0, mload(o)), allowed_))
o := add(o, 1)
if iszero(and(result, lt(o, end))) { break }
}
}
}
}
/// @dev Converts the bytes in the 7-bit ASCII string `s` to
/// an allowed lookup for use in `is7BitASCII(s, allowed)`.
/// To save runtime gas, you can cache the result in an immutable variable.
function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := or(result, shl(byte(0, mload(o)), 1))
o := add(o, 1)
if iszero(lt(o, end)) { break }
}
if shr(128, result) {
mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`.
revert(0x1c, 0x04)
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// For performance and bytecode compactness, byte string operations are restricted
// to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.
// Usage of byte string operations on charsets with runes spanning two or more bytes
// can lead to undefined behavior.
/// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
function replace(string memory subject, string memory needle, string memory replacement)
internal
pure
returns (string memory)
{
return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement)));
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.indexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle) internal pure returns (uint256) {
return LibBytes.indexOf(bytes(subject), bytes(needle), 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.contains(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.startsWith(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.endsWith(bytes(subject), bytes(needle));
}
/// @dev Returns `subject` repeated `times`.
function repeat(string memory subject, uint256 times) internal pure returns (string memory) {
return string(LibBytes.repeat(bytes(subject), times));
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(string memory subject, uint256 start, uint256 end)
internal
pure
returns (string memory)
{
return string(LibBytes.slice(bytes(subject), start, end));
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
/// `start` is a byte offset.
function slice(string memory subject, uint256 start) internal pure returns (string memory) {
return string(LibBytes.slice(bytes(subject), start, type(uint256).max));
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(string memory subject, string memory needle)
internal
pure
returns (uint256[] memory)
{
return LibBytes.indicesOf(bytes(subject), bytes(needle));
}
/// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
function split(string memory subject, string memory delimiter)
internal
pure
returns (string[] memory result)
{
bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter));
/// @solidity memory-safe-assembly
assembly {
result := a
}
}
/// @dev Returns a concatenated string of `a` and `b`.
/// Cheaper than `string.concat()` and does not de-align the free memory pointer.
function concat(string memory a, string memory b) internal pure returns (string memory) {
return string(LibBytes.concat(bytes(a), bytes(b)));
}
/// @dev Returns a copy of the string in either lowercase or UPPERCASE.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function toCase(string memory subject, bool toUpper)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(subject)
if n {
result := mload(0x40)
let o := add(result, 0x20)
let d := sub(subject, result)
let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
for { let end := add(o, n) } 1 {} {
let b := byte(0, mload(add(d, o)))
mstore8(o, xor(and(shr(b, flags), 0x20), b))
o := add(o, 1)
if eq(o, end) { break }
}
mstore(result, n) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
}
/// @dev Returns a string from a small bytes32 string.
/// `s` must be null-terminated, or behavior will be undefined.
function fromSmallString(bytes32 s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let n := 0
for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'.
mstore(result, n) // Store the length.
let o := add(result, 0x20)
mstore(o, s) // Store the bytes of the string.
mstore(add(o, n), 0) // Zeroize the slot after the string.
mstore(0x40, add(result, 0x40)) // Allocate memory.
}
}
/// @dev Returns the small string, with all bytes after the first null byte zeroized.
function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'.
mstore(0x00, s)
mstore(result, 0x00)
result := mload(0x00)
}
}
/// @dev Returns the string as a normalized null-terminated small string.
function toSmallString(string memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(s)
if iszero(lt(result, 33)) {
mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.
revert(0x1c, 0x04)
}
result := shl(shl(3, sub(32, result)), mload(add(s, result)))
}
}
/// @dev Returns a lowercased copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function lower(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, false);
}
/// @dev Returns an UPPERCASED copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function upper(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, true);
}
/// @dev Escapes the string to be used within HTML tags.
function escapeHTML(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let end := add(s, mload(s))
let o := add(result, 0x20)
// Store the bytes of the packed offsets and strides into the scratch space.
// `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
mstore(0x1f, 0x900094)
mstore(0x08, 0xc0000000a6ab)
// Store ""&'<>" into the scratch space.
mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// Not in `["\"","'","&","<",">"]`.
if iszero(and(shl(c, 1), 0x500000c400000000)) {
mstore8(o, c)
o := add(o, 1)
continue
}
let t := shr(248, mload(c))
mstore(o, mload(and(t, 0x1f)))
o := add(o, shr(5, t))
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
/// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
function escapeJSON(string memory s, bool addDoubleQuotes)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let o := add(result, 0x20)
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
// Store "\\u0000" in scratch space.
// Store "0123456789abcdef" in scratch space.
// Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
// into the scratch space.
mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
// Bitmask for detecting `["\"","\\"]`.
let e := or(shl(0x22, 1), shl(0x5c, 1))
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
if iszero(lt(c, 0x20)) {
if iszero(and(shl(c, 1), e)) {
// Not in `["\"","\\"]`.
mstore8(o, c)
o := add(o, 1)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), c)
o := add(o, 2)
continue
}
if iszero(and(shl(c, 1), 0x3700)) {
// Not in `["\b","\t","\n","\f","\d"]`.
mstore8(0x1d, mload(shr(4, c))) // Hex value.
mstore8(0x1e, mload(and(c, 15))) // Hex value.
mstore(o, mload(0x19)) // "\\u00XX".
o := add(o, 6)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), mload(add(c, 8)))
o := add(o, 2)
}
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
function escapeJSON(string memory s) internal pure returns (string memory result) {
result = escapeJSON(s, false);
}
/// @dev Encodes `s` so that it can be safely used in a URI,
/// just like `encodeURIComponent` in JavaScript.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
/// See: https://datatracker.ietf.org/doc/html/rfc2396
/// See: https://datatracker.ietf.org/doc/html/rfc3986
function encodeURIComponent(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Store "0123456789ABCDEF" in scratch space.
// Uppercased to be consistent with JavaScript's implementation.
mstore(0x0f, 0x30313233343536373839414243444546)
let o := add(result, 0x20)
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// If not in `[0-9A-Z-a-z-_.!~*'()]`.
if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) {
mstore8(o, 0x25) // '%'.
mstore8(add(o, 1), mload(and(shr(4, c), 15)))
mstore8(add(o, 2), mload(and(c, 15)))
o := add(o, 3)
continue
}
mstore8(o, c)
o := add(o, 1)
}
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @dev Returns whether `a` equals `b`.
function eq(string memory a, string memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.
function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
/// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
function cmp(string memory a, string memory b) internal pure returns (int256) {
return LibBytes.cmp(bytes(a), bytes(b));
}
/// @dev Packs a single string with its length into a single word.
/// Returns `bytes32(0)` if the length is zero or greater than 31.
function packOne(string memory a) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
// We don't need to zero right pad the string,
// since this is our own custom non-standard packing scheme.
result :=
mul(
// Load the length and the bytes.
mload(add(a, 0x1f)),
// `length != 0 && length < 32`. Abuses underflow.
// Assumes that the length is valid and within the block gas limit.
lt(sub(mload(a), 1), 0x1f)
)
}
}
/// @dev Unpacks a string packed using {packOne}.
/// Returns the empty string if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packOne}, the output behavior is undefined.
function unpackOne(bytes32 packed) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40) // Grab the free memory pointer.
mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes).
mstore(result, 0) // Zeroize the length slot.
mstore(add(result, 0x1f), packed) // Store the length and bytes.
mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes.
}
}
/// @dev Packs two strings with their lengths into a single word.
/// Returns `bytes32(0)` if combined length is zero or greater than 30.
function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let aLen := mload(a)
// We don't need to zero right pad the strings,
// since this is our own custom non-standard packing scheme.
result :=
mul(
or( // Load the length and the bytes of `a` and `b`.
shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))),
// `totalLen != 0 && totalLen < 31`. Abuses underflow.
// Assumes that the lengths are valid and within the block gas limit.
lt(sub(add(aLen, mload(b)), 1), 0x1e)
)
}
}
/// @dev Unpacks strings packed using {packTwo}.
/// Returns the empty strings if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packTwo}, the output behavior is undefined.
function unpackTwo(bytes32 packed)
internal
pure
returns (string memory resultA, string memory resultB)
{
/// @solidity memory-safe-assembly
assembly {
resultA := mload(0x40) // Grab the free memory pointer.
resultB := add(resultA, 0x40)
// Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
mstore(0x40, add(resultB, 0x40))
// Zeroize the length slots.
mstore(resultA, 0)
mstore(resultB, 0)
// Store the lengths and bytes.
mstore(add(resultA, 0x1f), packed)
mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
// Right pad with zeroes.
mstore(add(add(resultA, 0x20), mload(resultA)), 0)
mstore(add(add(resultB, 0x20), mload(resultB)), 0)
}
}
/// @dev Directly returns `a` without copying.
function directReturn(string memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the string does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the string is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the string.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
}pragma solidity ^0.8.27;
import "../25-handler/IBCMsgs.sol";
interface IIBCChannel {
/**
* @dev channelOpenInit is called by a module to initiate a channel opening handshake with a module on another chain.
*/
function channelOpenInit(
IBCMsgs.MsgChannelOpenInit calldata msg_
) external returns (uint32);
/**
* @dev channelOpenTry is called by a module to accept the first step of a channel opening handshake initiated by a module on another chain.
*/
function channelOpenTry(
IBCMsgs.MsgChannelOpenTry calldata msg_
) external returns (uint32);
/**
* @dev channelOpenAck is called by the handshake-originating module to acknowledge the acceptance of the initial request by the counterparty module on the other chain.
*/
function channelOpenAck(
IBCMsgs.MsgChannelOpenAck calldata msg_
) external;
/**
* @dev channelOpenConfirm is called by the counterparty module to close their end of the channel, since the other end has been closed.
*/
function channelOpenConfirm(
IBCMsgs.MsgChannelOpenConfirm calldata msg_
) external;
/**
* @dev channelCloseInit is called by either module to close their end of the channel. Once closed, channels cannot be reopened.
*/
function channelCloseInit(
IBCMsgs.MsgChannelCloseInit calldata msg_
) external;
/**
* @dev channelCloseConfirm is called by the counterparty module to close their end of the
* channel, since the other end has been closed.
*/
function channelCloseConfirm(
IBCMsgs.MsgChannelCloseConfirm calldata msg_
) external;
}pragma solidity ^0.8.27;
import "../25-handler/IBCMsgs.sol";
interface IIBCPacketSend {
/**
* @dev sendPacket is called by a module in order to send an IBC packet on a channel.
* The packet sequence generated for the packet to be sent is returned. An error
* is returned if one occurs.
*/
function sendPacket(
uint32 sourceChannel,
uint64 timeoutHeight,
uint64 timeoutTimestamp,
bytes calldata data
) external returns (IBCPacket memory packet);
}
interface IIBCPacketRecv {
/**
* @dev recvPacket is called by a module in order to receive & process an IBC packet
* sent on the corresponding channel end on the counterparty chain.
*/
function recvPacket(
IBCMsgs.MsgPacketRecv calldata msg_
) external;
}
interface IIBCPacketIntentRecv {
/**
* @dev recvIntentPacket is called by a module in order to receive & process an IBC intent packet
* for an IBC packet sent on the corresponding channel end on the counterparty chain.
* Note that no verification is done by the handler, the protocol must ensure that the market maker fulfilling the intent executes the expected effects.
*/
function recvIntentPacket(
IBCMsgs.MsgIntentPacketRecv calldata msg_
) external;
}
interface IIBCPacketWriteAck {
/**
* @dev writeAcknowledgement writes the packet execution acknowledgement to the state,
* which will be verified by the counterparty chain using AcknowledgePacket.
*/
function writeAcknowledgement(
IBCPacket calldata packet,
bytes memory acknowledgement
) external;
}
interface IIBCPacketAck {
/**
* @dev AcknowledgePacket is called by a module to process the acknowledgement of a
* packet previously sent by the calling module on a channel to a counterparty
* module on the counterparty chain. Its intended usage is within the ante
* handler. AcknowledgePacket will clean up the packet commitment,
* which is no longer necessary since the packet has been received and acted upon.
* It will also increment NextSequenceAck in case of ORDERED channels.
*/
function acknowledgePacket(
IBCMsgs.MsgPacketAcknowledgement calldata msg_
) external;
}
interface IIBCPacketTimeout {
/**
* @dev timeoutPacket is called by a module in order to receive & process an IBC packet
* sent on the corresponding channel end on the counterparty chain.
*/
function timeoutPacket(
IBCMsgs.MsgPacketTimeout calldata msg_
) external;
}
interface IIBCPacketBatchSend {
/**
* @dev batchSend is called by a module in order to commit multiple IBC packets that have been previously sent.
* An error occur if any of the packets wasn't sent.
* If successful, a new commitment is registered for the batch.
*/
function batchSend(
IBCMsgs.MsgBatchSend calldata msg_
) external;
}
interface IIBCPacketBatchAck {
/**
* @dev batchAcks is called by a module in order to commit multiple IBC packets acknowledgements.
* An error occur if any of the packets wasn't received.
* If successful, a new commitment is registered for the batch.
*/
function batchAcks(
IBCMsgs.MsgBatchAcks calldata msg_
) external;
}
interface IIBCModulePacket is IIBCPacketSend, IIBCPacketWriteAck {}
interface IIBCPacket is
IIBCPacketSend,
IIBCPacketRecv,
IIBCPacketIntentRecv,
IIBCPacketWriteAck,
IIBCPacketAck,
IIBCPacketTimeout,
IIBCPacketBatchSend,
IIBCPacketBatchAck,
IIBCModulePacket
{}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @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 Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, bytes memory returndata) = recipient.call{value: amount}("");
if (!success) {
_revert(returndata);
}
}
/**
* @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
* {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value);
}
(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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}.
*/
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
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAuthority.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard interface for permissioning originally defined in Dappsys.
*/
interface IAuthority {
/**
* @dev Returns true if the caller can invoke on a target the function identified by a function selector.
*/
function canCall(address caller, address target, bytes4 selector) external view returns (bool allowed);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0-rc.0) (access/manager/AuthorityUtils.sol)
pragma solidity ^0.8.20;
import {IAuthority} from "./IAuthority.sol";
library AuthorityUtils {
/**
* @dev Since `AccessManager` implements an extended IAuthority interface, invoking `canCall` with backwards compatibility
* for the preexisting `IAuthority` interface requires special care to avoid reverting on insufficient return data.
* This helper function takes care of invoking `canCall` in a backwards compatible way without reverting.
*/
function canCallWithDelay(
address authority,
address caller,
address target,
bytes4 selector
) internal view returns (bool immediate, uint32 delay) {
bytes memory data = abi.encodeCall(IAuthority.canCall, (caller, target, selector));
assembly ("memory-safe") {
mstore(0x00, 0x00)
mstore(0x20, 0x00)
if staticcall(gas(), authority, add(data, 0x20), mload(data), 0x00, 0x40) {
immediate := mload(0x00)
delay := mload(0x20)
// If delay does not fit in a uint32, return 0 (no delay)
// equivalent to: if gt(delay, 0xFFFFFFFF) { delay := 0 }
delay := mul(delay, iszero(shr(32, delay)))
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/manager/IAccessManager.sol)
pragma solidity ^0.8.20;
import {Time} from "../../utils/types/Time.sol";
interface IAccessManager {
/**
* @dev A delayed operation was scheduled.
*/
event OperationScheduled(
bytes32 indexed operationId,
uint32 indexed nonce,
uint48 schedule,
address caller,
address target,
bytes data
);
/**
* @dev A scheduled operation was executed.
*/
event OperationExecuted(bytes32 indexed operationId, uint32 indexed nonce);
/**
* @dev A scheduled operation was canceled.
*/
event OperationCanceled(bytes32 indexed operationId, uint32 indexed nonce);
/**
* @dev Informational labelling for a roleId.
*/
event RoleLabel(uint64 indexed roleId, string label);
/**
* @dev Emitted when `account` is granted `roleId`.
*
* NOTE: The meaning of the `since` argument depends on the `newMember` argument.
* If the role is granted to a new member, the `since` argument indicates when the account becomes a member of the role,
* otherwise it indicates the execution delay for this account and roleId is updated.
*/
event RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, bool newMember);
/**
* @dev Emitted when `account` membership or `roleId` is revoked. Unlike granting, revoking is instantaneous.
*/
event RoleRevoked(uint64 indexed roleId, address indexed account);
/**
* @dev Role acting as admin over a given `roleId` is updated.
*/
event RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin);
/**
* @dev Role acting as guardian over a given `roleId` is updated.
*/
event RoleGuardianChanged(uint64 indexed roleId, uint64 indexed guardian);
/**
* @dev Grant delay for a given `roleId` will be updated to `delay` when `since` is reached.
*/
event RoleGrantDelayChanged(uint64 indexed roleId, uint32 delay, uint48 since);
/**
* @dev Target mode is updated (true = closed, false = open).
*/
event TargetClosed(address indexed target, bool closed);
/**
* @dev Role required to invoke `selector` on `target` is updated to `roleId`.
*/
event TargetFunctionRoleUpdated(address indexed target, bytes4 selector, uint64 indexed roleId);
/**
* @dev Admin delay for a given `target` will be updated to `delay` when `since` is reached.
*/
event TargetAdminDelayUpdated(address indexed target, uint32 delay, uint48 since);
error AccessManagerAlreadyScheduled(bytes32 operationId);
error AccessManagerNotScheduled(bytes32 operationId);
error AccessManagerNotReady(bytes32 operationId);
error AccessManagerExpired(bytes32 operationId);
error AccessManagerLockedRole(uint64 roleId);
error AccessManagerBadConfirmation();
error AccessManagerUnauthorizedAccount(address msgsender, uint64 roleId);
error AccessManagerUnauthorizedCall(address caller, address target, bytes4 selector);
error AccessManagerUnauthorizedConsume(address target);
error AccessManagerUnauthorizedCancel(address msgsender, address caller, address target, bytes4 selector);
error AccessManagerInvalidInitialAdmin(address initialAdmin);
/**
* @dev Check if an address (`caller`) is authorised to call a given function on a given contract directly (with
* no restriction). Additionally, it returns the delay needed to perform the call indirectly through the {schedule}
* & {execute} workflow.
*
* This function is usually called by the targeted contract to control immediate execution of restricted functions.
* Therefore we only return true if the call can be performed without any delay. If the call is subject to a
* previously set delay (not zero), then the function should return false and the caller should schedule the operation
* for future execution.
*
* If `immediate` is true, the delay can be disregarded and the operation can be immediately executed, otherwise
* the operation can be executed if and only if delay is greater than 0.
*
* NOTE: The IAuthority interface does not include the `uint32` delay. This is an extension of that interface that
* is backward compatible. Some contracts may thus ignore the second return argument. In that case they will fail
* to identify the indirect workflow, and will consider calls that require a delay to be forbidden.
*
* NOTE: This function does not report the permissions of the admin functions in the manager itself. These are defined by the
* {AccessManager} documentation.
*/
function canCall(
address caller,
address target,
bytes4 selector
) external view returns (bool allowed, uint32 delay);
/**
* @dev Expiration delay for scheduled proposals. Defaults to 1 week.
*
* IMPORTANT: Avoid overriding the expiration with 0. Otherwise every contract proposal will be expired immediately,
* disabling any scheduling usage.
*/
function expiration() external view returns (uint32);
/**
* @dev Minimum setback for all delay updates, with the exception of execution delays. It
* can be increased without setback (and reset via {revokeRole} in the case event of an
* accidental increase). Defaults to 5 days.
*/
function minSetback() external view returns (uint32);
/**
* @dev Get whether the contract is closed disabling any access. Otherwise role permissions are applied.
*
* NOTE: When the manager itself is closed, admin functions are still accessible to avoid locking the contract.
*/
function isTargetClosed(address target) external view returns (bool);
/**
* @dev Get the role required to call a function.
*/
function getTargetFunctionRole(address target, bytes4 selector) external view returns (uint64);
/**
* @dev Get the admin delay for a target contract. Changes to contract configuration are subject to this delay.
*/
function getTargetAdminDelay(address target) external view returns (uint32);
/**
* @dev Get the id of the role that acts as an admin for the given role.
*
* The admin permission is required to grant the role, revoke the role and update the execution delay to execute
* an operation that is restricted to this role.
*/
function getRoleAdmin(uint64 roleId) external view returns (uint64);
/**
* @dev Get the role that acts as a guardian for a given role.
*
* The guardian permission allows canceling operations that have been scheduled under the role.
*/
function getRoleGuardian(uint64 roleId) external view returns (uint64);
/**
* @dev Get the role current grant delay.
*
* Its value may change at any point without an event emitted following a call to {setGrantDelay}.
* Changes to this value, including effect timepoint are notified in advance by the {RoleGrantDelayChanged} event.
*/
function getRoleGrantDelay(uint64 roleId) external view returns (uint32);
/**
* @dev Get the access details for a given account for a given role. These details include the timepoint at which
* membership becomes active, and the delay applied to all operation by this user that requires this permission
* level.
*
* Returns:
* [0] Timestamp at which the account membership becomes valid. 0 means role is not granted.
* [1] Current execution delay for the account.
* [2] Pending execution delay for the account.
* [3] Timestamp at which the pending execution delay will become active. 0 means no delay update is scheduled.
*/
function getAccess(
uint64 roleId,
address account
) external view returns (uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect);
/**
* @dev Check if a given account currently has the permission level corresponding to a given role. Note that this
* permission might be associated with an execution delay. {getAccess} can provide more details.
*/
function hasRole(uint64 roleId, address account) external view returns (bool isMember, uint32 executionDelay);
/**
* @dev Give a label to a role, for improved role discoverability by UIs.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleLabel} event.
*/
function labelRole(uint64 roleId, string calldata label) external;
/**
* @dev Add `account` to `roleId`, or change its execution delay.
*
* This gives the account the authorization to call any function that is restricted to this role. An optional
* execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation
* that is restricted to members of this role. The user will only be able to execute the operation after the delay has
* passed, before it has expired. During this period, admin and guardians can cancel the operation (see {cancel}).
*
* If the account has already been granted this role, the execution delay will be updated. This update is not
* immediate and follows the delay rules. For example, if a user currently has a delay of 3 hours, and this is
* called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any
* operation executed in the 3 hours that follows this update was indeed scheduled before this update.
*
* Requirements:
*
* - the caller must be an admin for the role (see {getRoleAdmin})
* - granted role must not be the `PUBLIC_ROLE`
*
* Emits a {RoleGranted} event.
*/
function grantRole(uint64 roleId, address account, uint32 executionDelay) external;
/**
* @dev Remove an account from a role, with immediate effect. If the account does not have the role, this call has
* no effect.
*
* Requirements:
*
* - the caller must be an admin for the role (see {getRoleAdmin})
* - revoked role must not be the `PUBLIC_ROLE`
*
* Emits a {RoleRevoked} event if the account had the role.
*/
function revokeRole(uint64 roleId, address account) external;
/**
* @dev Renounce role permissions for the calling account with immediate effect. If the sender is not in
* the role this call has no effect.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* Emits a {RoleRevoked} event if the account had the role.
*/
function renounceRole(uint64 roleId, address callerConfirmation) external;
/**
* @dev Change admin role for a given role.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleAdminChanged} event
*/
function setRoleAdmin(uint64 roleId, uint64 admin) external;
/**
* @dev Change guardian role for a given role.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleGuardianChanged} event
*/
function setRoleGuardian(uint64 roleId, uint64 guardian) external;
/**
* @dev Update the delay for granting a `roleId`.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleGrantDelayChanged} event.
*/
function setGrantDelay(uint64 roleId, uint32 newDelay) external;
/**
* @dev Set the role required to call functions identified by the `selectors` in the `target` contract.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {TargetFunctionRoleUpdated} event per selector.
*/
function setTargetFunctionRole(address target, bytes4[] calldata selectors, uint64 roleId) external;
/**
* @dev Set the delay for changing the configuration of a given target contract.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {TargetAdminDelayUpdated} event.
*/
function setTargetAdminDelay(address target, uint32 newDelay) external;
/**
* @dev Set the closed flag for a contract.
*
* Closing the manager itself won't disable access to admin methods to avoid locking the contract.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {TargetClosed} event.
*/
function setTargetClosed(address target, bool closed) external;
/**
* @dev Return the timepoint at which a scheduled operation will be ready for execution. This returns 0 if the
* operation is not yet scheduled, has expired, was executed, or was canceled.
*/
function getSchedule(bytes32 id) external view returns (uint48);
/**
* @dev Return the nonce for the latest scheduled operation with a given id. Returns 0 if the operation has never
* been scheduled.
*/
function getNonce(bytes32 id) external view returns (uint32);
/**
* @dev Schedule a delayed operation for future execution, and return the operation identifier. It is possible to
* choose the timestamp at which the operation becomes executable as long as it satisfies the execution delays
* required for the caller. The special value zero will automatically set the earliest possible time.
*
* Returns the `operationId` that was scheduled. Since this value is a hash of the parameters, it can reoccur when
* the same parameters are used; if this is relevant, the returned `nonce` can be used to uniquely identify this
* scheduled operation from other occurrences of the same `operationId` in invocations of {execute} and {cancel}.
*
* Emits a {OperationScheduled} event.
*
* NOTE: It is not possible to concurrently schedule more than one operation with the same `target` and `data`. If
* this is necessary, a random byte can be appended to `data` to act as a salt that will be ignored by the target
* contract if it is using standard Solidity ABI encoding.
*/
function schedule(
address target,
bytes calldata data,
uint48 when
) external returns (bytes32 operationId, uint32 nonce);
/**
* @dev Execute a function that is delay restricted, provided it was properly scheduled beforehand, or the
* execution delay is 0.
*
* Returns the nonce that identifies the previously scheduled operation that is executed, or 0 if the
* operation wasn't previously scheduled (if the caller doesn't have an execution delay).
*
* Emits an {OperationExecuted} event only if the call was scheduled and delayed.
*/
function execute(address target, bytes calldata data) external payable returns (uint32);
/**
* @dev Cancel a scheduled (delayed) operation. Returns the nonce that identifies the previously scheduled
* operation that is cancelled.
*
* Requirements:
*
* - the caller must be the proposer, a guardian of the targeted function, or a global admin
*
* Emits a {OperationCanceled} event.
*/
function cancel(address caller, address target, bytes calldata data) external returns (uint32);
/**
* @dev Consume a scheduled operation targeting the caller. If such an operation exists, mark it as consumed
* (emit an {OperationExecuted} event and clean the state). Otherwise, throw an error.
*
* This is useful for contract that want to enforce that calls targeting them were scheduled on the manager,
* with all the verifications that it implies.
*
* Emit a {OperationExecuted} event.
*/
function consumeScheduledOp(address caller, bytes calldata data) external;
/**
* @dev Hashing function for delayed operations.
*/
function hashOperation(address caller, address target, bytes calldata data) external view returns (bytes32);
/**
* @dev Changes the authority of a target managed by this manager instance.
*
* Requirements:
*
* - the caller must be a global admin
*/
function updateAuthority(address target, address newAuthority) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAccessManaged.sol)
pragma solidity ^0.8.20;
interface IAccessManaged {
/**
* @dev Authority that manages this contract was updated.
*/
event AuthorityUpdated(address authority);
error AccessManagedUnauthorized(address caller);
error AccessManagedRequiredDelay(address caller, uint32 delay);
error AccessManagedInvalidAuthority(address authority);
/**
* @dev Returns the current authority.
*/
function authority() external view returns (address);
/**
* @dev Transfers control to a new authority. The caller must be the current authority.
*/
function setAuthority(address) external;
/**
* @dev Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is
* being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs
* attacker controlled calls.
*/
function isConsumingScheduledOp() external view returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
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;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for byte related operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol)
library LibBytes {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated bytes storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct BytesStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the bytes.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the bytes storage `$` to `s`.
function set(BytesStorage storage $, bytes memory s) internal {
/// @solidity memory-safe-assembly
assembly {
let n := mload(s)
let packed := or(0xff, shl(8, n))
for { let i := 0 } 1 {} {
if iszero(gt(n, 0xfe)) {
i := 0x1f
packed := or(n, shl(8, mload(add(s, i))))
if iszero(gt(n, i)) { break }
}
let o := add(s, 0x20)
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), mload(add(o, i)))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to `s`.
function setCalldata(BytesStorage storage $, bytes calldata s) internal {
/// @solidity memory-safe-assembly
assembly {
let packed := or(0xff, shl(8, s.length))
for { let i := 0 } 1 {} {
if iszero(gt(s.length, 0xfe)) {
i := 0x1f
packed := or(s.length, shl(8, shr(8, calldataload(s.offset))))
if iszero(gt(s.length, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), calldataload(add(s.offset, i)))
i := add(i, 0x20)
if iszero(lt(i, s.length)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to the empty bytes.
function clear(BytesStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty bytes "".
function isEmpty(BytesStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(BytesStorage storage $) internal view returns (uint256 result) {
result = uint256($._spacer);
/// @solidity memory-safe-assembly
assembly {
let n := and(0xff, result)
result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n))))
}
}
/// @dev Returns the value stored in `$`.
function get(BytesStorage storage $) internal view returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let o := add(result, 0x20)
let packed := sload($.slot)
let n := shr(8, packed)
for { let i := 0 } 1 {} {
if iszero(eq(or(packed, 0xff), packed)) {
mstore(o, packed)
n := and(0xff, packed)
i := 0x1f
if iszero(gt(n, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
mstore(add(o, i), sload(add(p, shr(5, i))))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
mstore(result, n) // Store the length of the memory.
mstore(add(o, n), 0) // Zeroize the slot after the bytes.
mstore(0x40, add(add(o, n), 0x20)) // Allocate memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTES OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
function replace(bytes memory subject, bytes memory needle, bytes memory replacement)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let needleLen := mload(needle)
let replacementLen := mload(replacement)
let d := sub(result, subject) // Memory difference.
let i := add(subject, 0x20) // Subject bytes pointer.
mstore(0x00, add(i, mload(subject))) // End of subject.
if iszero(gt(needleLen, mload(subject))) {
let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, needleLen), h)) {
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
j := add(j, 0x20)
if iszero(lt(j, replacementLen)) { break }
}
d := sub(add(d, replacementLen), needleLen)
if needleLen {
i := add(i, needleLen)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
}
let end := mload(0x00)
let n := add(sub(d, add(result, 0x20)), end)
// Copy the rest of the bytes one word at a time.
for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
let o := add(i, d)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
for { let subjectLen := mload(subject) } 1 {} {
if iszero(mload(needle)) {
result := from
if iszero(gt(from, subjectLen)) { break }
result := subjectLen
break
}
let needleLen := mload(needle)
let subjectStart := add(subject, 0x20)
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
let s := mload(add(needle, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }
if iszero(lt(needleLen, 0x20)) {
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, subjectStart)
break
}
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
for {} 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
result := sub(subject, subjectStart)
break
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) {
return indexOf(subject, needle, 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
result := not(0) // Initialize to `NOT_FOUND`.
let needleLen := mload(needle)
if gt(needleLen, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), needleLen)
if iszero(gt(fromMax, from)) { from := fromMax }
let end := add(add(subject, 0x20), w)
subject := add(add(subject, 0x20), from)
if iszero(gt(subject, end)) { break }
// As this function is not too often used,
// we shall simply use keccak256 for smaller bytecode size.
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, add(end, 1))
break
}
subject := add(subject, w) // `sub(subject, 1)`.
if iszero(gt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256)
{
return lastIndexOf(subject, needle, type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) {
return indexOf(subject, needle) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
// Just using keccak256 directly is actually cheaper.
let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n))
result := lt(gt(n, mload(subject)), t)
}
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
let notInRange := gt(n, mload(subject))
// `subject + 0x20 + max(subject.length - needle.length, 0)`.
let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n)))
// Just using keccak256 directly is actually cheaper.
result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(bytes memory subject, uint256 times)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(or(iszero(times), iszero(l))) {
result := mload(0x40)
subject := add(subject, 0x20)
let o := add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(o, j), mload(add(subject, j)))
j := add(j, 0x20)
if iszero(lt(j, l)) { break }
}
o := add(o, l)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(bytes memory subject, uint256 start, uint256 end)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(gt(l, end)) { end := l }
if iszero(gt(l, start)) { start := l }
if lt(start, end) {
result := mload(0x40)
let n := sub(end, start)
let i := add(subject, start)
let w := not(0x1f)
// Copy the `subject` one word at a time, backwards.
for { let j := and(add(n, 0x1f), w) } 1 {} {
mstore(add(result, j), mload(add(i, j)))
j := add(j, w) // `sub(j, 0x20)`.
if iszero(j) { break }
}
let o := add(add(result, 0x20), n)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset.
function slice(bytes memory subject, uint256 start)
internal
pure
returns (bytes memory result)
{
result = slice(subject, start, type(uint256).max);
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start, uint256 end)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, subject.length), lt(subject.length, end)))
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, end), sub(end, start))
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, subject.length), sub(subject.length, start))
}
}
/// @dev Reduces the size of `subject` to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncate(bytes memory subject, uint256 n)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := subject
mstore(mul(lt(n, mload(result)), result), n)
}
}
/// @dev Returns a copy of `subject`, with the length reduced to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncatedCalldata(bytes calldata subject, uint256 n)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
result.offset := subject.offset
result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n)))
}
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256[] memory result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLen := mload(needle)
if iszero(gt(searchLen, mload(subject))) {
result := mload(0x40)
let i := add(subject, 0x20)
let o := add(result, 0x20)
let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, searchLen), h)) {
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
o := add(o, 0x20)
i := add(i, searchLen) // Advance `i` by `searchLen`.
if searchLen {
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(o, 0x20))
}
}
}
/// @dev Returns a arrays of bytess based on the `delimiter` inside of the `subject` bytes.
function split(bytes memory subject, bytes memory delimiter)
internal
pure
returns (bytes[] memory result)
{
uint256[] memory indices = indicesOf(subject, delimiter);
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
let indexPtr := add(indices, 0x20)
let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
mstore(add(indicesEnd, w), mload(subject))
mstore(indices, add(mload(indices), 1))
for { let prevIndex := 0 } 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let l := sub(index, prevIndex)
mstore(element, l) // Store the length of the element.
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(l, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes.
// Allocate memory for the length and the bytes, rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(l, 0x3f), w)))
mstore(indexPtr, element) // Store the `element` into the array.
}
prevIndex := add(index, mload(delimiter))
indexPtr := add(indexPtr, 0x20)
if iszero(lt(indexPtr, indicesEnd)) { break }
}
result := indices
if iszero(mload(delimiter)) {
result := add(indices, 0x20)
mstore(result, sub(mload(indices), 2))
}
}
}
/// @dev Returns a concatenated bytes of `a` and `b`.
/// Cheaper than `bytes.concat()` and does not de-align the free memory pointer.
function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let w := not(0x1f)
let aLen := mload(a)
// Copy `a` one word at a time, backwards.
for { let o := and(add(aLen, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let bLen := mload(b)
let output := add(result, aLen)
// Copy `b` one word at a time, backwards.
for { let o := and(add(bLen, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let totalLen := add(aLen, bLen)
let last := add(add(result, 0x20), totalLen)
mstore(last, 0) // Zeroize the slot after the bytes.
mstore(result, totalLen) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate memory.
}
}
/// @dev Returns whether `a` equals `b`.
function eq(bytes memory a, bytes memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes.
function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
/// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) {
/// @solidity memory-safe-assembly
assembly {
let aLen := mload(a)
let bLen := mload(b)
let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f))
if n {
for { let i := 0x20 } 1 {} {
let x := mload(add(a, i))
let y := mload(add(b, i))
if iszero(or(xor(x, y), eq(i, n))) {
i := add(i, 0x20)
continue
}
result := sub(gt(x, y), lt(x, y))
break
}
}
// forgefmt: disable-next-item
if iszero(result) {
let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0)))
let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0)))
result := sub(gt(x, y), lt(x, y))
if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) }
}
}
}
/// @dev Directly returns `a` without copying.
function directReturn(bytes memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the bytes does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the bytes is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the bytes.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
/// @dev Directly returns `a` with minimal copying.
function directReturn(bytes[] memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let n := mload(a) // `a.length`.
let o := add(a, 0x20) // Start of elements in `a`.
let u := a // Highest memory slot.
let w := not(0x1f)
for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } {
let c := add(o, shl(5, i)) // Location of pointer to `a[i]`.
let s := mload(c) // `a[i]`.
let l := mload(s) // `a[i].length`.
let r := and(l, 0x1f) // `a[i].length % 32`.
let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`.
// If `s` comes before `o`, or `s` is not zero right padded.
if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) {
let m := mload(0x40)
mstore(m, l) // Copy `a[i].length`.
for {} 1 {} {
mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards.
z := add(z, w) // `sub(z, 0x20)`.
if iszero(z) { break }
}
let e := add(add(m, 0x20), l)
mstore(e, 0) // Zeroize the slot after the copied bytes.
mstore(0x40, add(e, 0x20)) // Allocate memory.
s := m
}
mstore(c, sub(s, o)) // Convert to calldata offset.
let t := add(l, add(s, 0x20))
if iszero(lt(t, u)) { u := t }
}
let retStart := add(a, w) // Assumes `a` doesn't start from scratch space.
mstore(retStart, 0x20) // Store the return offset.
return(retStart, add(0x40, sub(u, retStart))) // End the transaction.
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(add(add(a, 0x20), offset))
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
function loadCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
result := calldataload(add(a.offset, offset))
}
}
/// @dev Returns a slice representing a static struct in the calldata. Performs bounds checks.
function staticStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
result.offset := add(a.offset, offset)
result.length := sub(a.length, offset)
if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks.
function dynamicStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(a.offset, s)
result.length := sub(a.length, s)
if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns bytes in calldata. Performs bounds checks.
function bytesInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(add(a.offset, s), 0x20)
result.length := calldataload(add(a.offset, s))
// forgefmt: disable-next-item
if or(shr(64, or(result.length, or(s, or(l, a.offset)))),
or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) }
}
}
/// @dev Returns empty calldata bytes. For silencing the compiler.
function emptyCalldata() internal pure returns (bytes calldata result) {
/// @solidity memory-safe-assembly
assembly {
result.length := 0
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/types/Time.sol)
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
import {SafeCast} from "../math/SafeCast.sol";
/**
* @dev This library provides helpers for manipulating time-related objects.
*
* It uses the following types:
* - `uint48` for timepoints
* - `uint32` for durations
*
* While the library doesn't provide specific types for timepoints and duration, it does provide:
* - a `Delay` type to represent duration that can be programmed to change value automatically at a given point
* - additional helper functions
*/
library Time {
using Time for *;
/**
* @dev Get the block timestamp as a Timepoint.
*/
function timestamp() internal view returns (uint48) {
return SafeCast.toUint48(block.timestamp);
}
/**
* @dev Get the block number as a Timepoint.
*/
function blockNumber() internal view returns (uint48) {
return SafeCast.toUint48(block.number);
}
// ==================================================== Delay =====================================================
/**
* @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the
* future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value.
* This allows updating the delay applied to some operation while keeping some guarantees.
*
* In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for
* some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set
* the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should
* still apply for some time.
*
*
* The `Delay` type is 112 bits long, and packs the following:
*
* ```
* | [uint48]: effect date (timepoint)
* | | [uint32]: value before (duration)
* ↓ ↓ ↓ [uint32]: value after (duration)
* 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC
* ```
*
* NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently
* supported.
*/
type Delay is uint112;
/**
* @dev Wrap a duration into a Delay to add the one-step "update in the future" feature
*/
function toDelay(uint32 duration) internal pure returns (Delay) {
return Delay.wrap(duration);
}
/**
* @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled
* change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered.
*/
function _getFullAt(
Delay self,
uint48 timepoint
) private pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
(valueBefore, valueAfter, effect) = self.unpack();
return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect);
}
/**
* @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the
* effect timepoint is 0, then the pending value should not be considered.
*/
function getFull(Delay self) internal view returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
return _getFullAt(self, timestamp());
}
/**
* @dev Get the current value.
*/
function get(Delay self) internal view returns (uint32) {
(uint32 delay, , ) = self.getFull();
return delay;
}
/**
* @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to
* enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the
* new delay becomes effective.
*/
function withUpdate(
Delay self,
uint32 newValue,
uint32 minSetback
) internal view returns (Delay updatedDelay, uint48 effect) {
uint32 value = self.get();
uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0));
effect = timestamp() + setback;
return (pack(value, newValue, effect), effect);
}
/**
* @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint).
*/
function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
uint112 raw = Delay.unwrap(self);
valueAfter = uint32(raw);
valueBefore = uint32(raw >> 32);
effect = uint48(raw >> 64);
return (valueBefore, valueAfter, effect);
}
/**
* @dev pack the components into a Delay object.
*/
function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) {
return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0-rc.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}{
"remappings": [
"@openzeppelin-foundry-upgradeable/=libs/@openzeppelin-foundry-upgradeable/",
"@openzeppelin-upgradeable/=libs/@openzeppelin-upgradeable/",
"@openzeppelin/=libs/@openzeppelin/",
"forge-std/=libs/forge-std/",
"solady/=libs/solady/",
"solidity-bytes-utils/=libs/solidity-bytes-utils/contracts/",
"solidity-stringutils/=libs/solidity-stringutils/src/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"authority","type":"address"}],"name":"AccessManagedInvalidAuthority","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"uint32","name":"delay","type":"uint32"}],"name":"AccessManagedRequiredDelay","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"AccessManagedUnauthorized","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"ErrAcknowledgementAlreadyExists","type":"error"},{"inputs":[],"name":"ErrAcknowledgementIsEmpty","type":"error"},{"inputs":[],"name":"ErrBatchSameChannelOnly","type":"error"},{"inputs":[],"name":"ErrClientNotFound","type":"error"},{"inputs":[],"name":"ErrClientTypeAlreadyExists","type":"error"},{"inputs":[],"name":"ErrClientTypeNotFound","type":"error"},{"inputs":[],"name":"ErrCommittedAckNotPresent","type":"error"},{"inputs":[],"name":"ErrInvalidChannelState","type":"error"},{"inputs":[],"name":"ErrInvalidConnectionState","type":"error"},{"inputs":[],"name":"ErrInvalidProof","type":"error"},{"inputs":[],"name":"ErrLatestTimestampNotFound","type":"error"},{"inputs":[],"name":"ErrModuleNotFound","type":"error"},{"inputs":[],"name":"ErrNotEnoughPackets","type":"error"},{"inputs":[],"name":"ErrPacketAlreadyAcknowledged","type":"error"},{"inputs":[],"name":"ErrPacketAlreadyExist","type":"error"},{"inputs":[],"name":"ErrPacketCommitmentNotFound","type":"error"},{"inputs":[],"name":"ErrPacketNotReceived","type":"error"},{"inputs":[],"name":"ErrTimeoutHeightUnsupported","type":"error"},{"inputs":[],"name":"ErrTimeoutMustBeSet","type":"error"},{"inputs":[],"name":"ErrTimeoutTimestampNotReached","type":"error"},{"inputs":[],"name":"ErrTimestampTimeout","type":"error"},{"inputs":[],"name":"ErrUnauthorized","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"authority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"batchHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"packetHash","type":"bytes32"}],"name":"BatchedPreviouslyAcked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"batchHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"packetHash","type":"bytes32"}],"name":"BatchedPreviouslySent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"portId","type":"address"},{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"}],"name":"ChannelCloseConfirm","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"portId","type":"address"},{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"}],"name":"ChannelCloseInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"portId","type":"address"},{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"connectionId","type":"uint32"}],"name":"ChannelOpenAck","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"portId","type":"address"},{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"connectionId","type":"uint32"}],"name":"ChannelOpenConfirm","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"portId","type":"address"},{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":true,"internalType":"string","name":"versionIndex","type":"string"},{"indexed":false,"internalType":"string","name":"version","type":"string"}],"name":"ChannelOpenInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"portId","type":"address"},{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":true,"internalType":"string","name":"counterpartyVersionIndex","type":"string"},{"indexed":false,"internalType":"string","name":"counterpartyVersion","type":"string"}],"name":"ChannelOpenTry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"counterpartyClientId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"counterpartyConnectionId","type":"uint32"}],"name":"ConnectionOpenAck","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"counterpartyClientId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"counterpartyConnectionId","type":"uint32"}],"name":"ConnectionOpenConfirm","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"counterpartyClientId","type":"uint32"}],"name":"ConnectionOpenInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"counterpartyClientId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"counterpartyConnectionId","type":"uint32"}],"name":"ConnectionOpenTry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"clientTypeIndex","type":"string"},{"indexed":false,"internalType":"string","name":"clientType","type":"string"},{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"string","name":"counterpartyChainId","type":"string"}],"name":"CreateClient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"packetHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"bytes","name":"makerMsg","type":"bytes"}],"name":"IntentPacketRecv","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"}],"name":"Misbehaviour","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"packetHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"acknowledgement","type":"bytes"},{"indexed":true,"internalType":"address","name":"maker","type":"address"}],"name":"PacketAck","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"packetHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"bytes","name":"makerMsg","type":"bytes"}],"name":"PacketRecv","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"packetHash","type":"bytes32"},{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint32","name":"destinationChannelId","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"indexed":false,"internalType":"struct IBCPacket","name":"packet","type":"tuple"}],"name":"PacketSend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"packetHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"}],"name":"PacketTimeout","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"clientTypeIndex","type":"string"},{"indexed":false,"internalType":"string","name":"clientType","type":"string"},{"indexed":false,"internalType":"address","name":"clientAddress","type":"address"}],"name":"RegisterClient","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"uint64","name":"height","type":"uint64"}],"name":"UpdateClient","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"packetHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"acknowledgement","type":"bytes"}],"name":"WriteAck","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint32","name":"destinationChannelId","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct IBCPacket[]","name":"packets","type":"tuple[]"},{"internalType":"bytes[]","name":"acknowledgements","type":"bytes[]"},{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgPacketAcknowledgement","name":"msg_","type":"tuple"}],"name":"acknowledgePacket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint32","name":"destinationChannelId","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct IBCPacket[]","name":"packets","type":"tuple[]"},{"internalType":"bytes[]","name":"acks","type":"bytes[]"}],"internalType":"struct IBCMsgs.MsgBatchAcks","name":"msg_","type":"tuple"}],"name":"batchAcks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint32","name":"destinationChannelId","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct IBCPacket[]","name":"packets","type":"tuple[]"}],"internalType":"struct IBCMsgs.MsgBatchSend","name":"msg_","type":"tuple"}],"name":"batchSend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"channelId","type":"uint32"},{"internalType":"bytes","name":"proofInit","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgChannelCloseConfirm","name":"msg_","type":"tuple"}],"name":"channelCloseConfirm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"channelId","type":"uint32"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgChannelCloseInit","name":"msg_","type":"tuple"}],"name":"channelCloseInit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"channelId","type":"uint32"},{"internalType":"string","name":"counterpartyVersion","type":"string"},{"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"},{"internalType":"bytes","name":"proofTry","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgChannelOpenAck","name":"msg_","type":"tuple"}],"name":"channelOpenAck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"channelId","type":"uint32"},{"internalType":"bytes","name":"proofAck","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgChannelOpenConfirm","name":"msg_","type":"tuple"}],"name":"channelOpenConfirm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"portId","type":"address"},{"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"internalType":"uint32","name":"connectionId","type":"uint32"},{"internalType":"string","name":"version","type":"string"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgChannelOpenInit","name":"msg_","type":"tuple"}],"name":"channelOpenInit","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"portId","type":"address"},{"components":[{"internalType":"enum IBCChannelState","name":"state","type":"uint8"},{"internalType":"uint32","name":"connectionId","type":"uint32"},{"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"},{"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"internalType":"string","name":"version","type":"string"}],"internalType":"struct IBCChannel","name":"channel","type":"tuple"},{"internalType":"string","name":"counterpartyVersion","type":"string"},{"internalType":"bytes","name":"proofInit","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgChannelOpenTry","name":"msg_","type":"tuple"}],"name":"channelOpenTry","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"channelOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"channels","outputs":[{"internalType":"enum IBCChannelState","name":"state","type":"uint8"},{"internalType":"uint32","name":"connectionId","type":"uint32"},{"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"},{"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"internalType":"string","name":"version","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"clientImpls","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"clientRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"clientTypes","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"commitments","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"connectionId","type":"uint32"},{"internalType":"uint32","name":"counterpartyConnectionId","type":"uint32"},{"internalType":"bytes","name":"proofTry","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"}],"internalType":"struct IBCMsgs.MsgConnectionOpenAck","name":"msg_","type":"tuple"}],"name":"connectionOpenAck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"connectionId","type":"uint32"},{"internalType":"bytes","name":"proofAck","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"}],"internalType":"struct IBCMsgs.MsgConnectionOpenConfirm","name":"msg_","type":"tuple"}],"name":"connectionOpenConfirm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"uint32","name":"counterpartyClientId","type":"uint32"}],"internalType":"struct IBCMsgs.MsgConnectionOpenInit","name":"msg_","type":"tuple"}],"name":"connectionOpenInit","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"counterpartyClientId","type":"uint32"},{"internalType":"uint32","name":"counterpartyConnectionId","type":"uint32"},{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bytes","name":"proofInit","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"}],"internalType":"struct IBCMsgs.MsgConnectionOpenTry","name":"msg_","type":"tuple"}],"name":"connectionOpenTry","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"connections","outputs":[{"internalType":"enum IBCConnectionState","name":"state","type":"uint8"},{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"uint32","name":"counterpartyClientId","type":"uint32"},{"internalType":"uint32","name":"counterpartyConnectionId","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"clientType","type":"string"},{"internalType":"bytes","name":"clientStateBytes","type":"bytes"},{"internalType":"bytes","name":"consensusStateBytes","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgCreateClient","name":"msg_","type":"tuple"}],"name":"createClient","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"channelId","type":"uint32"},{"internalType":"string","name":"counterpartyVersion","type":"string"},{"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"},{"internalType":"bytes","name":"proofTry","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgChannelOpenAck","name":"msg_","type":"tuple"}],"name":"forceChannelOpenAck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"channelId","type":"uint32"},{"internalType":"bytes","name":"proofAck","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgChannelOpenConfirm","name":"msg_","type":"tuple"}],"name":"forceChannelOpenConfirm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"portId","type":"address"},{"components":[{"internalType":"enum IBCChannelState","name":"state","type":"uint8"},{"internalType":"uint32","name":"connectionId","type":"uint32"},{"internalType":"uint32","name":"counterpartyChannelId","type":"uint32"},{"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"internalType":"string","name":"version","type":"string"}],"internalType":"struct IBCChannel","name":"channel","type":"tuple"},{"internalType":"string","name":"counterpartyVersion","type":"string"},{"internalType":"bytes","name":"proofInit","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgChannelOpenTry","name":"msg_","type":"tuple"}],"name":"forceChannelOpenTry","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"connectionId","type":"uint32"},{"internalType":"uint32","name":"counterpartyConnectionId","type":"uint32"},{"internalType":"bytes","name":"proofTry","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"}],"internalType":"struct IBCMsgs.MsgConnectionOpenAck","name":"msg_","type":"tuple"}],"name":"forceConnectionOpenAck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"connectionId","type":"uint32"},{"internalType":"bytes","name":"proofAck","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"}],"internalType":"struct IBCMsgs.MsgConnectionOpenConfirm","name":"msg_","type":"tuple"}],"name":"forceConnectionOpenConfirm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"counterpartyClientId","type":"uint32"},{"internalType":"uint32","name":"counterpartyConnectionId","type":"uint32"},{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bytes","name":"proofInit","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"}],"internalType":"struct IBCMsgs.MsgConnectionOpenTry","name":"msg_","type":"tuple"}],"name":"forceConnectionOpenTry","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bytes","name":"clientStateBytes","type":"bytes"},{"internalType":"bytes","name":"consensusStateBytes","type":"bytes"}],"internalType":"struct IBCMsgs.MsgForceUpdateClient","name":"msg_","type":"tuple"}],"name":"forceUpdateClient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"}],"name":"getClient","outputs":[{"internalType":"contract ILightClient","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gitRev","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"authority","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isConsumingScheduledOp","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bytes","name":"clientMessage","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgMisbehaviour","name":"msg_","type":"tuple"}],"name":"misbehaviour","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint32","name":"destinationChannelId","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct IBCPacket[]","name":"packets","type":"tuple[]"},{"internalType":"bytes[]","name":"marketMakerMsgs","type":"bytes[]"},{"internalType":"address","name":"marketMaker","type":"address"}],"internalType":"struct IBCMsgs.MsgIntentPacketRecv","name":"msg_","type":"tuple"}],"name":"recvIntentPacket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint32","name":"destinationChannelId","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct IBCPacket[]","name":"packets","type":"tuple[]"},{"internalType":"bytes[]","name":"relayerMsgs","type":"bytes[]"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"}],"internalType":"struct IBCMsgs.MsgPacketRecv","name":"msg_","type":"tuple"}],"name":"recvPacket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"clientType","type":"string"},{"internalType":"contract ILightClient","name":"client","type":"address"}],"name":"registerClient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"sendPacket","outputs":[{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint32","name":"destinationChannelId","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct IBCPacket","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint32","name":"destinationChannelId","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct IBCPacket","name":"packet","type":"tuple"},{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"uint64","name":"proofHeight","type":"uint64"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgPacketTimeout","name":"msg_","type":"tuple"}],"name":"timeoutPacket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bytes","name":"clientMessage","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IBCMsgs.MsgUpdateClient","name":"msg_","type":"tuple"}],"name":"updateClient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"internalType":"uint32","name":"destinationChannelId","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint64","name":"timeoutHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct IBCPacket","name":"packet","type":"tuple"},{"internalType":"bytes","name":"acknowledgement","type":"bytes"}],"name":"writeAcknowledgement","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a080604052346100c257306080525f516020615fb05f395f51905f525460ff8160401c166100b3576002600160401b03196001600160401b03821601610060575b604051615ee990816100c78239608051818181612a300152612ae60152f35b6001600160401b0319166001600160401b039081175f516020615fb05f395f51905f525581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80610041565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe60c06040526004361015610011575f80fd5b5f3560e01c80630d27062c14613b045780630e04968414613784578063113a1b70146136d55780631184fa02146136755780631296c1481461362257806317cad5cc146135f557806318c19870146134be5780632b2c54631461336657806336853d6d1461327957806343085db114613165578063441fd11514612d8b5780634f1ef28614612aa857806352d1902d14612a165780635501032e146129575780635f5d288e146129195780636415d1a3146127b5578063653c1b5e1461274157806378890388146125875780637a9e5e4b146124cc5780637fc254f41461249f57806381408dfd146122ad57806382a09c1514612091578063839df945146120685780638a65334614611d4d5780638fb3603714611cba578063990491a514611c4a578063999d5c6b14611ae75780639aa0346f1461175f5780639f18077b14611631578063ad3cb1cc146115d2578063afc3619b1461125c578063b1892e40146111f8578063b2b16d1c14611182578063b69562bd14610fba578063bf7e214f14610f75578063c4d66de814610cc7578063d36623ad14610c30578063d937c37914610c0e578063de844ebc14610bd0578063dea5a72314610ba1578063dee97dc6146109f4578063e1dc07c614610958578063e5cbff7914610727578063fb407dca1461065d5763fed12cbf14610208575f80fd5b346105845761021636613d6f565b6102203633614376565b6001600160a01b0360206102348380613f7e565b91908260405193849283378101600181520301902054168015610635577f9b9820486a05c0193efb214c6c2ba8fce02c5a5c84aa057f8199c99f13ff939b5f525f60205263ffffffff60405f2054169063ffffffff61029283614e73565b7f9b9820486a05c0193efb214c6c2ba8fce02c5a5c84aa057f8199c99f13ff939b5f908152602052167fa17c46f2d2a87aa05f956999001178d4f3a177d856047a83ccebd64d7a2ef49d556102e78380613f7e565b835f52600260205260405f209167ffffffffffffffff821161060857610317826103118554613c01565b85614095565b5f90601f831160011461059e578261040e95935f959361034b938792610593575b50505f198260011b9260031b1c19161790565b90555b8382526003602052604082206001600160a01b0382167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790556103986020860186613f7e565b838660606001600160a01b036104208b6103c46103bb6040839b9a9b0183613f7e565b95909201613f55565b936040519b8c9a8b998a987f384a3c30000000000000000000000000000000000000000000000000000000008a523360048b015260248a015260a060448a015260a4890191614039565b91600319878403016064880152614039565b9116608483015203925af1908115610588575f905f926104fb575b50907f03f4bda014b6bddaa31ba73f9e94f6bf6b7ba5b4f9c65b67640800c2b62964316020948385945161046e8661508b565b5f525f885260405f205561049467ffffffffffffffff60408984015193015116866150b6565b5f525f875260405f20556104b76104f06104ae8380613f7e565b92909380613f7e565b92909381604051928392833781015f8152039020946104e3604051948594604086526040860191614039565b908382038a850152613b85565b0390a3604051908152f35b9150503d805f833e61050d8183613d0c565b810190608081830312610584576105248282614135565b9060608101519067ffffffffffffffff821161058457019180601f840112156105845760209461057b7f03f4bda014b6bddaa31ba73f9e94f6bf6b7ba5b4f9c65b67640800c2b62964319285888897519101614340565b9350945061043b565b5f80fd5b6040513d5f823e3d90fd5b013590505f80610338565b601f19831691845f5260205f20925f5b8181106105f0575092600192859261040e98965f9896106105d7575b505050811b01905561034e565b5f1960f88560031b161c199101351690555f80806105ca565b919360206001819287870135815501950192016105ae565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7faa478af9000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105845761066b36613baa565b6106e161067782614028565b6106b56040840163ffffffff61068c82614028565b816040519561069a87613cf0565b600187521660208601521660408401525f6060840152614028565b6106c160808501613f69565b6106ce6060860186613f7e565b916106db60208801614028565b93615b1d565b156106ff576106f1602091615bba565b63ffffffff60405191168152f35b7f14209932000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461058457608060031936011261058457610740613bdd565b6024359067ffffffffffffffff82168092036105845760443567ffffffffffffffff81168091036105845760643567ffffffffffffffff81116105845761078b903690600401613da2565b9390610795614315565b5081610930578215610908576107c58463ffffffff165f5260066020526001600160a01b0360405f205416331490565b156108e0576108059063ffffffff6107dc86615948565b5460281c169563ffffffff604051966107f488613cd4565b169687875260208701523691613e35565b60408401526060830152608082015261081d81615433565b61082681615514565b92835f525f60205260405f20546108b8576108b4935f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f20557f635b5d234fe7abddfb29b6c8498780a3175c9002c537f20a3d1bf9d0e625b5fe604051602081528061089d6020820187613eab565b0390a3604051918291602083526020830190613eab565b0390f35b7fa29bd6ea000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fcc12cef6000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fddd92f79000000000000000000000000000000000000000000000000000000005f5260045ffd5b7faf2726eb000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105845761096636613dd0565b61097761097282614028565b614c05565b6109e4815463ffffffff8160081c1663ffffffff61099486614028565b9281604051946109a386613cf0565b60038652818360281c1660208701528460408701521660608501526109ca60408801613f69565b6109d76020890189613f7e565b93909260481c1693615b1d565b156106ff576109f2916155d2565b005b3461058457610a0236613dd0565b610a0c3633614376565b6001600160a01b03610a25610a2083614028565b614e27565b16906060610a3282614028565b92610a406020840184613f7e565b91905f610a4f60408701613f55565b96610a8a604051988996879586947f8f2a49300000000000000000000000000000000000000000000000000000000086523360048701614059565b03925af1918215610588575f92610b2c575b50602063ffffffff67ffffffffffffffff610b1d7f078276040a4f9f4dea1214e38413d6bac929b39330be19599176564d23d5ef41948651610ae5610ae083614028565b61508b565b5f525f865260405f205584870151610b0e6040610b0184614028565b990198858a5116906150b6565b5f525f865260405f2055614028565b945116936040519485521692a2005b90915060603d606011610b9a575b610b448183613d0c565b8101906060818303126105845763ffffffff67ffffffffffffffff610b1d610b8f7f078276040a4f9f4dea1214e38413d6bac929b39330be19599176564d23d5ef4195602095614135565b959450505050610a9c565b503d610b3a565b34610584576020600319360112610584576020610bbf610a20613bdd565b6001600160a01b0360405191168152f35b346105845760206003193601126105845763ffffffff610bee613bdd565b165f52600660205260206001600160a01b0360405f205416604051908152f35b346105845760206106f1610c2136613baa565b610c2b3633614376565b615bba565b3461058457610c3e36613d6f565b610c4f610c4a82614028565b614bb4565b610cb9815463ffffffff8160081c1663ffffffff610c6c86614028565b8160405194610c7a86613cf0565b6002865260281c166020850152826040850152166060830152610c9f60608601613f69565b610cac6040870187613f7e565b916106db60208901614028565b156106ff576109f291614c2e565b3461058457602060031936011261058457610ce0613e03565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c16159167ffffffffffffffff821680159081610f6d575b6001149081610f63575b159081610f5a575b50610f3257818360017fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000610da69516177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055610edd575b50610d91615e06565b610d99615e06565b610da1615e06565b615534565b610dae615e06565b5f602081905260017fa17c46f2d2a87aa05f956999001178d4f3a177d856047a83ccebd64d7a2ef49d8190557fa948e29ac0e6a6a5e3c647a07a0505170c972dd4960cbe194aee77626bb52b588190557f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a9091527f24072874bb11662934f0c68ca2659a14efae71555bb48eba2450fe6433183f9555610e4a57005b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005583610d88565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b90501584610d31565b303b159150610d29565b849150610d1f565b34610584575f6003193601126105845760206001600160a01b037ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a005416604051908152f35b346105845760406003193601126105845763ffffffff610fd8614002565b165f52600560205260405f20805460ff811660058110156111555760030361112d5763ffffffff61100c9160081c16614cff565b50600460ff1982541617815561102981611024614002565b61500b565b63ffffffff611036614002565b165f5260066020526001600160a01b0360405f205416611054614002565b602435906001600160a01b038216820361058457823b15610584576040517f172d9c4800000000000000000000000000000000000000000000000000000000815233600482015263ffffffff9190911660248201526001600160a01b039190911660448201525f8160648183865af180156105885761111d575b507f5d4b57424fd8ef7d85bed4d570d10b0bf5d38ef1936569ba4ca1f62ff78836e563ffffffff6110fd614002565b61111882865460281c1660016040519485941697018361422e565b0390a3005b5f61112791613d0c565b826110ce565b7f96d09146000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b346105845761119036613d6f565b61119a3633614376565b63ffffffff6111a882614028565b165f52600560205260405f209060ff82541660058110156111555760020361112d576109f29163ffffffff6111dc83614028565b165f5260066020526001600160a01b0360405f2054169161584f565b346105845760206003193601126105845763ffffffff611216613bdd565b165f526004602052608060405f205463ffffffff6040519161123b8360ff8316613e89565b818160081c166020840152818160281c16604084015260481c166060820152f35b346105845761126a36613baa565b6112743633614376565b61127e8180613f01565b80929150156115aa576112918180613f01565b1561157d576112a3816112a892613fcf565b614028565b906112c463ffffffff6112ba84615948565b5460081c16614cff565b9261139160206112e56112e06112da8680613f01565b90615361565b615651565b95818501966112fd6112f78988613f01565b90615793565b915f61130b60608901613f69565b9161131960408a018a613f7e565b9790956001600160a01b0361132d84614e27565b16956040519089820152888152611345604082613d0c565b604051918983015288825261135b604083613d0c565b604051998a98899788967fa9f9396e00000000000000000000000000000000000000000000000000000000885260048801614d49565b03925af1908115610588575f9161154e575b50156106ff57916113b381615971565b6001600160a01b031691608081019163ffffffff16905f5b8581106113d457005b6113e8816113e28480613f01565b9061417f565b908363ffffffff6113f884614028565b160361152657611407826159bd565b61141b816114158a86613f01565b90614213565b9061142587613f55565b93883b15610584575f6040518080977f2cd66b6f000000000000000000000000000000000000000000000000000000008252336004830152608060248301526001600160a01b0361148f61147c608485018861429b565b6003198582030160448601528989614039565b911660648301520381838d5af1908115610588576114e26114dd7f41d958a7d93b50b1f7541c6fc345d0c4657b1e83497baa562c866611ac1f69bb926001988b95611516575b503690614196565b615433565b926001600160a01b036114f48b613f55565b169461150d604051928392602084526020840191614039565b0390a4016113cb565b5f61152091613d0c565b8f6114d5565b7f9629d3d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b611570915060203d602011611576575b6115688183613d0c565b810190614d31565b856113a3565b503d61155e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f5458d343000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610584575f600319360112610584576108b46040516115f3604082613d0c565b600581527f352e302e300000000000000000000000000000000000000000000000000000006020820152604051918291602083526020830190613b85565b346105845760406003193601126105845760043567ffffffffffffffff81116105845760a060031982360301126105845760243567ffffffffffffffff811161058457611682903690600401613e6b565b8051156117375760248201916116ba61169a84614028565b63ffffffff165f5260066020526001600160a01b0360405f205416331490565b156108e05761111863ffffffff61172161170e6114dd7f488830ba53f27b7033e966a79427476ad47d550358e894bafeef8b97c6559251956117036116fe8a614028565b615948565b503690600401614196565b956112a38661171c89615651565b615a7d565b1692604051918291602083526020830190613b85565b7f2430f403000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105845761176d36613d6f565b6117773633614376565b6117818180613fcf565b61178a81614028565b9161179c63ffffffff6112ba85615948565b916001600160a01b036117ae84614e27565b169260408301604460206117c183613f69565b96604051928380927fe9946fc300000000000000000000000000000000000000000000000000000000825267ffffffffffffffff63ffffffff89169b8c60048501521660248301525afa8015610588575f90611aa6575b67ffffffffffffffff915016918215611a7e576118353685614196565b61183e90615433565b9561184887615651565b9261185290613f69565b906118606020880188613f7e565b94909361186c90614e27565b6001600160a01b0316936040519160208301526020825261188e604083613d0c565b60405195869485947f3fd413de000000000000000000000000000000000000000000000000000000008652600486015267ffffffffffffffff166024850152604484016080905260848401906118e392614039565b8281036003190160648401526118f891613b85565b03815a6020945f91f1908115610588575f91611a5f575b50156106ff5761191e85615971565b90611928836159bd565b6080830167ffffffffffffffff61193e82613f69565b16156109085761195667ffffffffffffffff91613f69565b1611611a37576001600160a01b036060911692019161197483613f55565b91813b15610584575f916119cf836001600160a01b0393604051968795869485937f168ce11c00000000000000000000000000000000000000000000000000000000855233600486015260606024860152606485019061429b565b9116604483015203925af180156105885763ffffffff926001600160a01b03926119fe92611a27575b50613f55565b1692167f34df62ed9d26dbe71f13d2bd3f645d6cd16b0c44645ef783c2ed799748c80a745f80a4005b5f611a3191613d0c565b866119f8565b7f8551d235000000000000000000000000000000000000000000000000000000005f5260045ffd5b611a78915060203d602011611576576115688183613d0c565b8661190f565b7f9b6c9adc000000000000000000000000000000000000000000000000000000005f5260045ffd5b506020813d602011611adf575b81611ac060209383613d0c565b8101031261058457611ada67ffffffffffffffff91614120565b611818565b3d9150611ab3565b3461058457611af536613d6f565b63ffffffff611b0382614028565b165f52600560205260405f209081549160ff831660058110156111555760020361112d57611c3263ffffffff8460081c16611b3d81614cff565b63ffffffff611b4b86614028565b165f52600660205263ffffffff60405f205496611b89611b6a88614028565b9463ffffffff165f52600460205263ffffffff60405f205460481c1690565b9382604051917fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008b60601b16602084015260148352611bc9603484613d0c565b8160405197611bd789613cd4565b600389521660208801521660408601526060850152604051611c0781611c008160028b01613c52565b0382613d0c565b6080850152611c1860408801613f69565b611c256020890189613f7e565b93909260281c1693614d9d565b156106ff576001600160a01b036109f293169161584f565b346105845760206003193601126105845760043567ffffffffffffffff81116105845736602382011215610584576001600160a01b03602080611c9881943690602481600401359101613e35565b604051928184925191829101835e810160018152030190205416604051908152f35b34610584575f600319360112610584577ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a005460a01c60ff1615611d455760207f8fb36037000000000000000000000000000000000000000000000000000000005b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b60205f611d1b565b3461058457611d8e611d5e36613dd0565b611d683633614376565b611d728180613f01565b929091611d8160408201613f55565b6080526020810190613f01565b9083156115aa57611daa6020611da48580613fcf565b01614028565b93611dbc63ffffffff6112ba87615948565b50611dc685615971565b5f633b9aca0042029267ffffffffffffffff428504633b9aca0014421517159416915b818110611df257005b611dfd81838a61417f565b90602082019163ffffffff8b1663ffffffff611e1885614028565b16036115265767ffffffffffffffff611e3360608301613f69565b16610930578661203b5767ffffffffffffffff611e5260808301613f69565b1685101561201357611e676114dd3683614196565b90611e7182615651565b90815f525f602052878b8b60405f20541580611fe1575b611e9d575b5050505050506001915001611de9565b6001600160a01b039793611ef99593611eb9895f958695614213565b94819b86946040519a8b96879586937f6f104830000000000000000000000000000000000000000000000000000000008552608051903360048701614618565b0393165af19384156105885760019786915f96611fbd575b507fdbb36eab1a905641d6490533e8dfb257a8633c9a26a166c0954a1fc59d7946b7611f6763ffffffff611f4488614028565b1692604051918291602083526001600160a01b0360805116976020840191614039565b0390a48251611f7a575b50878b8b611e8d565b63ffffffff6117217f488830ba53f27b7033e966a79427476ad47d550358e894bafeef8b97c6559251936112a386611fb195615a7d565b0390a38a808080611f71565b611fda9196503d805f833e611fd28183613d0c565b8101906145e1565b945f611f11565b855f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f2055611e88565b7fa4821270000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b34610584576020600319360112610584576004355f525f602052602060405f2054604051908152f35b346105845761209f36613d6f565b63ffffffff6120ad82614028565b165f52600560205260405f209081549060ff821660058110156111555760030361112d576121d263ffffffff8360081c166120e781614cff565b63ffffffff6120f585614028565b165f52600660205263ffffffff60405f2054956001600160a01b038716968261213f61212089614028565b9663ffffffff165f52600460205263ffffffff60405f205460481c1690565b957fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519360601b1660208401526014835261217d603484613d0c565b816040519761218b89613cd4565b6004895216602088015216604086015260608501526040516121b481611c008160028d01613c52565b60808501526121c560408701613f69565b611c256020880188613f7e565b156106ff57600460ff198454161783556121ef8361102483614028565b6121f881614028565b61220460608301613f55565b90833b15610584576040517f40380c6100000000000000000000000000000000000000000000000000000000815233600482015263ffffffff9190911660248201526001600160a01b039190911660448201525f8160648183875af18015610588577ff55ea0b61aba75ba1463c3325f7b0a06baa2d96ee4a621a05dabdf03b489c41d9263ffffffff926110fd9261229d575b50614028565b5f6122a791613d0c565b86612297565b346105845760206003193601126105845760043567ffffffffffffffff811161058457806004019060406003198236030112610584576122ed3633614376565b6122f78280613f01565b919050600282106115aa5761230c8380613f01565b1561157d576020611da48261232093613fcf565b9161232e6112da8580613f01565b602463ffffffff5f95169301935b82811061237057856123616112e06112da61235a6112f78a86613f01565b9380613f01565b5f525f60205260405f20555f80f35b61237e816113e28880613f01565b908061245f575b6114dd6123a3612399836114158a8c613f01565b9290943690614196565b926123ad84615651565b5f525f60205260405f20549182158015612436575b611737576123da916123d5913691613e35565b615671565b0361240e5760019183867fdf2b8ea755edd621da990db5273e5ac28efcd0462a19552a690540f9ef63b14f5f80a40161233c565b7f59c3580a000000000000000000000000000000000000000000000000000000005f5260045ffd5b507f010000000000000000000000000000000000000000000000000000000000000083146123c2565b8463ffffffff61247160208501614028565b1614612385577f9629d3d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610584576109f26124b036613dd0565b6124ba3633614376565b6124c661097282614028565b906155d2565b34610584576020600319360112610584576124e5613e03565b6001600160a01b037ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a005416330361255b57803b15612526576109f290615534565b6001600160a01b03907fc2f31e5e000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b7f068ca9d8000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b346105845760206003193601126105845760043567ffffffffffffffff8111610584576020600319826004019236030112610584576125c63633614376565b6125d08180613f01565b919050600282106115aa576125e58180613f01565b1561157d576112a3816125f792613fcf565b916126056112da8380613f01565b9163ffffffff5f9416935b8281106126505761262084615514565b5f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f20555f80f35b61265e816113e28480613f01565b81612704575b6114dd612672913690614196565b9061267c82615514565b5f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f2054036126dc5760019185877f8ffe8d45aea2ea970a08903423957c59d26de1fb69c2928b63562c13ccd5e3cb5f80a401612610565b7f4d7cfc57000000000000000000000000000000000000000000000000000000005f5260045ffd5b8563ffffffff61271383614028565b1614612664577f9629d3d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105845761274f36613d3c565b6127593633614376565b63ffffffff61276782614028565b165f52600560205260ff60405f20541660058110156111555760010361112d578063ffffffff6127996109f293614028565b165f5260066020526001600160a01b0360405f20541690615118565b34610584576127c336613d3c565b63ffffffff6127d182614028565b165f52600560205260405f205460ff811660058110156111555760010361112d5760081c63ffffffff169061290161280883614cff565b9263ffffffff61281784614028565b165f52600660205260405f2054936128d061285361283486614028565b9363ffffffff165f52600460205263ffffffff60405f205460481c1690565b9263ffffffff6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008960601b16602082015260148152612896603482613d0c565b6128a36020890189613f7e565b92909381604051986128b48a613cd4565b60028a5216602089015216604087015260608601523691613e35565b60808301526128e160808501613f69565b6128ee6060860186613f7e565b916128fb60408801614028565b93614d9d565b156106ff576001600160a01b036109f2921690615118565b346105845760206003193601126105845763ffffffff612937613bdd565b165f52600360205260206001600160a01b0360405f205416604051908152f35b346105845761296536613dd0565b61296f3633614376565b6001600160a01b03612983610a2083614028565b169060605f61299183614028565b9363ffffffff6129a46020860186613f7e565b939096610a8a6129b76040890189613f7e565b612a046040519b8c998a9889977f446005b80000000000000000000000000000000000000000000000000000000089523360048a0152166024880152608060448801526084870191614039565b91600319858403016064860152614039565b34610584575f600319360112610584576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003612a805760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b7fe07c8dba000000000000000000000000000000000000000000000000000000005f5260045ffd5b604060031936011261058457612abc613e03565b60243567ffffffffffffffff811161058457612adc903690600401613e6b565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803014908115612d56575b50612a8057612b203633614376565b6001600160a01b038216916040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481875afa5f9181612d22575b50612b9357837f4c9c8ce3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc859203612cf75750813b15612ccc57807fffffffffffffffffffffffff00000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2815115612c9b575f808360206109f295519101845af43d15612c93573d91612c7783613e19565b92612c856040519485613d0c565b83523d5f602085013e615e5d565b606091615e5d565b505034612ca457005b7fb398979f000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4c9c8ce3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7faa1d49a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091506020813d602011612d4e575b81612d3e60209383613d0c565b8101031261058457519085612b62565b3d9150612d31565b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416141583612b11565b3461058457612d9936613baa565b60408101612dae612da982614028565b614cff565b50612db7614f7d565b9063ffffffff821691825f52600560205260405f2093600160ff19865416178555612e1a612de484614028565b86547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1660089190911b64ffffffff0016178655565b60608101612e288183613f7e565b600288019167ffffffffffffffff821161060857612e4a826103118554613c01565b5f90601f831160011461310157612e7692915f91836130f65750505f198260011b9260031b1c19161790565b90555b612e866020830183613f7e565b60018801979167ffffffffffffffff821161060857612eaf82612ea98b54613c01565b8b614095565b5f90601f831160011461308e579180612ee092612ee995945f926130835750505f198260011b9260031b1c19161790565b88555b8461500b565b612f3b83612ef684613f55565b9063ffffffff165f5260066020526001600160a01b0360405f2091167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6001600160a01b03612f4c83613f55565b1692612f5785614028565b90612f628385613f7e565b959091612f7160808701613f55565b823b15610584575f94612fb686926040519a8b97889687957f10cac64800000000000000000000000000000000000000000000000000000000875233600488016140e4565b03925af1928315610588576020966130687f370d54a331c7da62dbd4e3f464f8ca9b0c4726640604fcb08cd4cfb5ed41d03393613053938997613073575b5061300761300187613f55565b98614028565b906001600160a01b0361302561301d838a613f7e565b939099613f7e565b92909881604051928392833781015f81520390209963ffffffff604051978897606089526060890190613c52565b94168d87015285840360408701521696614039565b0390a4604051908152f35b5f61307d91613d0c565b8a612ff4565b013590508b80610338565b601f198316918a5f5260205f20925f5b8181106130de5750916001939185612ee9979694106130c5575b505050811b018855612ee3565b5f1960f88560031b161c199101351690558a80806130b8565b9193602060018192878701358155019501920161309e565b013590508a80610338565b601f19831691845f5260205f20925f5b81811061314d5750908460019594939210613134575b505050811b019055612e79565b5f1960f88560031b161c19910135169055898080613127565b91936020600181928787013581550195019201613111565b34610584576040600319360112610584576020613180614e8b565b61322d63ffffffff821691825f526004845260405f20906131d86131a2614002565b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1660089190911b64ffffffff0016178355565b600160ff198354161782556132286131ee614015565b83547fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff1660289190911b68ffffffff000000000016178355565b614f19565b613235614002565b817f5c19396f17b2d5b8ebfa9d37569101115f64e85557fe202593aa3e5555bad05d8463ffffffff613265614015565b9481604051961686521693a3604051908152f35b346105845761328736613dd0565b6132913633614376565b6001600160a01b036132a5610a2083614028565b16906132b081614028565b6132bd6020830183613f7e565b90936132cb60408501613f55565b94813b15610584575f8094613310604051988996879586947f553931740000000000000000000000000000000000000000000000000000000086523360048701614059565b03925af19081156105885763ffffffff9261332f926133565750614028565b167f2d86933ea68552f2484167a027c9e1a658fee909dffcc151fb2d4fde750311265f80a2005b5f61336091613d0c565b83612297565b346105845761337436613d3c565b602081016133828183613fcf565b356005811015610584577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0161112d57806133c8612da96020611da46134ae9587613fcf565b611da46133fb6133dd6020611da48689613fcf565b63ffffffff165f52600460205263ffffffff60405f205460481c1690565b9261348261340887613f55565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519160601b16602082015260148152613445603482613d0c565b6134526040890189613f7e565b909163ffffffff604051986134668a613cd4565b60018a521660208901525f604089015260608801523691613e35565b608085015261349360808701613f69565b6128fb60406134a560608a018a613f7e565b9590948a613fcf565b156106ff576106f1602091614655565b346105845760406003193601126105845760043567ffffffffffffffff8111610584576134ef903690600401613da2565b602435916001600160a01b0383168093036105845761350e3633614376565b6001600160a01b0360405183838237602081858101600181520301902054166135cd577f52dcd9fec0aa3ec676cc46ae22674ebc00b38c2e1c522b26910c5bdd76a3473c916040518183823760208183810160018152030190206001600160a01b0385167fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905560405181838237808281015f8152039020936135c2604051938493604085526040850191614039565b9060208301520390a2005b7f0c7cc9b9000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610584576109f261360636613d6f565b6136103633614376565b61361c610c4a82614028565b90614c2e565b346105845760206003193601126105845763ffffffff613640613bdd565b165f5260026020526108b4611c0061366160405f2060405192838092613c52565b604051918291602083526020830190613b85565b346105845761368336613d3c565b61368d3633614376565b61369a6020820182613fcf565b356005811015610584577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0161112d576106f1602091614655565b346105845760206003193601126105845763ffffffff6136f3613bdd565b165f52600560205263ffffffff60405f206108b4600261377683549361373e6040519161372e836137278160018501613c52565b0384613d0c565b6137276040518096819301613c52565b60405195856137518860ff819916613d2f565b818160081c16602088015260281c16604086015260a0606086015260a0850190613b85565b908382036080850152613b85565b346105845761379236613baa565b61379c3633614376565b6137a68180613f01565b6137b260408401613f55565b60a0526137c26020840184613f01565b916137dd6137d260808701613f69565b956060810190613f7e565b9082156115aa576020906137f582611da48980613fcf565b9761380763ffffffff6112ba8b615948565b905f61381b613816888c615361565b615514565b9261387f6001600160a01b0361383083614e27565b16946040519088820152878152613848604082613d0c565b604051907f01000000000000000000000000000000000000000000000000000000000000008983015288825261135b604083613d0c565b03925af1908115610588575f91613ae5575b50156106ff576138a085615971565b5f633b9aca0042029267ffffffffffffffff428504633b9aca0014421517159416915b8181106138cc57005b6138d781838a61417f565b90602082019163ffffffff8b1663ffffffff6138f285614028565b16036115265767ffffffffffffffff61390d60608301613f69565b16610930578661203b5767ffffffffffffffff61392c60808301613f69565b16851015612013576139416114dd3683614196565b9061394b82615651565b90815f525f602052878b8b60405f20541580613ab3575b613977575b50505050505060019150016138c3565b6001600160a01b0397936139d39593613993895f958695614213565b94819b86946040519a8b96879586937f667b822e00000000000000000000000000000000000000000000000000000000855260a051903360048701614618565b0393165af19384156105885760019786915f96613a97575b507fe450e03249d131499e278eeafd8e27effcceeb40b0b95628a087aa16b4b101d5613a4163ffffffff613a1e88614028565b1692604051918291602083526001600160a01b0360a05116976020840191614039565b0390a48251613a54575b50878b8b613967565b63ffffffff6117217f488830ba53f27b7033e966a79427476ad47d550358e894bafeef8b97c6559251936112a386613a8b95615a7d565b0390a38a808080613a4b565b613aac9196503d805f833e611fd28183613d0c565b945f6139eb565b855f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f2055613962565b613afe915060203d602011611576576115688183613d0c565b86613891565b34610584575f600319360112610584576108b4604051613b25606082613d0c565b602881527f373131336632363631303235383033303231663831396164643039393935666360208201527f653266353861626600000000000000000000000000000000000000000000000060408201526040519182916020835260208301905b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b6020600319820112610584576004359067ffffffffffffffff8211610584576003198260a0920301126105845760040190565b6004359063ffffffff8216820361058457565b359063ffffffff8216820361058457565b90600182811c92168015613c48575b6020831014613c1b57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691613c10565b5f9291815491613c6183613c01565b8083529260018116908115613cb65750600114613c7d57505050565b5f9081526020812093945091925b838310613c9c575060209250010190565b600181602092949394548385870101520191019190613c8b565b9050602094955060ff1991509291921683830152151560051b010190565b60a0810190811067ffffffffffffffff82111761060857604052565b6080810190811067ffffffffffffffff82111761060857604052565b90601f601f19910116810190811067ffffffffffffffff82111761060857604052565b9060058210156111555752565b6020600319820112610584576004359067ffffffffffffffff8211610584576003198260c0920301126105845760040190565b6020600319820112610584576004359067ffffffffffffffff821161058457600319826080920301126105845760040190565b9181601f840112156105845782359167ffffffffffffffff8311610584576020838186019501011161058457565b6020600319820112610584576004359067ffffffffffffffff821161058457600319826060920301126105845760040190565b600435906001600160a01b038216820361058457565b67ffffffffffffffff811161060857601f01601f191660200190565b929192613e4182613e19565b91613e4f6040519384613d0c565b829481845281830111610584578281602093845f960137010152565b9080601f8301121561058457816020613e8693359101613e35565b90565b9060048210156111555752565b359067ffffffffffffffff8216820361058457565b9063ffffffff825116815263ffffffff6020830151166020820152608067ffffffffffffffff81613eeb604086015160a0604087015260a0860190613b85565b9482606082015116606086015201511691015290565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610584570180359067ffffffffffffffff821161058457602001918160051b3603831361058457565b356001600160a01b03811681036105845790565b3567ffffffffffffffff811681036105845790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610584570180359067ffffffffffffffff82116105845760200191813603831361058457565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301821215610584570190565b60043563ffffffff811681036105845790565b60243563ffffffff811681036105845790565b3563ffffffff811681036105845790565b601f8260209493601f1993818652868601375f8582860101520116010190565b939260609363ffffffff6001600160a01b03948561408e959a999a168852166020870152608060408701526080860191614039565b9416910152565b601f82116140a257505050565b5f5260205f20906020601f840160051c830193106140da575b601f0160051c01905b8181106140cf575050565b5f81556001016140c4565b90915081906140bb565b9463ffffffff6001600160a01b03948161408e9587608099969c9b9c168a5216602089015216604087015260a0606087015260a0860191614039565b519067ffffffffffffffff8216820361058457565b9190826060910312610584576040516060810181811067ffffffffffffffff82111761060857604052604061417a818395805185526020810151602086015201614120565b910152565b9082101561157d57613e869160051b810190613fcf565b91909160a08184031261058457604051906141b082613cd4565b81936141bb82613bf0565b83526141c960208301613bf0565b602084015260408201359067ffffffffffffffff821161058457826141f76080949261417a94869401613e6b565b604086015261420860608201613e96565b606086015201613e96565b9082101561157d5761422a9160051b810190613f7e565b9091565b9063ffffffff61408e602092959495604085526040850190613c52565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561058457016020813591019167ffffffffffffffff821161058457813603831361058457565b9063ffffffff6142aa83613bf0565b16815263ffffffff6142be60208401613bf0565b166020820152608067ffffffffffffffff61430e826142f46142e3604088018861424b565b60a0604089015260a0880191614039565b958361430260608301613e96565b16606087015201613e96565b1691015290565b6040519061432282613cd4565b5f608083828152826020820152606060408201528260608201520152565b92919261434c82613e19565b9161435a6040519384613d0c565b829481845281830111610584578281602093845f96015e010152565b7ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a0054916001600160a01b0383169281600411610584575f5f9060405f8151966001600160a01b0360208901917fb700961300000000000000000000000000000000000000000000000000000000835216978860248201523060448201527fffffffff0000000000000000000000000000000000000000000000000000000083351660648201526064815261442b608482613d0c565b828052826020525190895afa6145ce575b15614449575b5050505050565b63ffffffff16156145a2577fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000177ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a0055823b15610584576020925f92836040518096819582947f94c7d7ee000000000000000000000000000000000000000000000000000000008452600484015260406024840152601f19601f6044850192808452808786860137868582860101520116010103925af1801561058857614592575b507fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff7ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a0054167ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a00555f80808080614442565b5f61459c91613d0c565b5f614521565b827f068ca9d8000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50505f516020518060201c15029061443c565b6020818303126105845780519067ffffffffffffffff821161058457019080601f83011215610584578151613e8692602001614340565b90614641613e86969495936001600160a01b03809316845260806020850152608084019061429b565b941660408201526060818503910152614039565b61465d614f7d565b906020810161466c8183613fcf565b9063ffffffff841691825f52600560205260405f20813560058110156105845760ff60ff1983541691161781556146de6146a860208401614028565b82547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1660089190911b64ffffffff0016178255565b6147276146ed60408401614028565b82547fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff1660289190911b68ffffffff000000000016178255565b600181016147386060840184613f7e565b9067ffffffffffffffff821161060857614756826103118554613c01565b5f90601f8311600114614b49578261479995936002959361478a935f926105935750505f198260011b9260031b1c19161790565b90555b01916080810190613f7e565b9067ffffffffffffffff8211610608576147b7826103118554613c01565b5f90601f8311600114614ae5576147e392915f91836105935750505f198260011b9260031b1c19161790565b90555b6147f08184613fcf565b6040516020810191602083528035906005821015610584576148aa839161481e6148b8946040850190613d2f565b63ffffffff61482f60208301613bf0565b16606084015263ffffffff61484660408301613bf0565b16608084015261487a61486f61485f606084018461424b565b60a08088015260e0870191614039565b91608081019061424b565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030160c0860152614039565b03601f198101835282613d0c565b5190206148c485615d2d565b5f525f60205260405f20556148dc84612ef685613f55565b6001600160a01b036148ed84613f55565b16906148fe6020611da48387613fcf565b9161490e6040611da48488613fcf565b9061492661491c8488613fcf565b6080810190613f7e565b9290946040880195614938878a613f7e565b61494460a08c01613f55565b92863b156105845760405197889687967f5101edc400000000000000000000000000000000000000000000000000000000885233600489015263ffffffff1660248801528c604488015263ffffffff1660648701526084860160e0905260e48601906149af92614039565b908482036003190160a48601526149c592614039565b906001600160a01b031660c483015203815a5f948591f1801561058857614ad5575b506149f184613f55565b936149fc8282613fcf565b60608101614a0991613f7e565b919092614a168183613fcf565b604001614a2290614028565b90614a2d9083613fcf565b602001614a3990614028565b96614a448684613f7e565b96614a4f9194613f7e565b96909381604051928392833781015f815203902097604051958695608087526080870190614a7c92614039565b9263ffffffff16602086015263ffffffff16604085015283820360608501526001600160a01b031694614aae92614039565b037f9856c775e40c73b8fdab7ee177e147e26a1ee9cda934ab9497a46da9ab5481ce91a490565b5f614adf91613d0c565b5f6149e7565b601f19831691845f5260205f20925f5b818110614b315750908460019594939210614b18575b505050811b0190556147e6565b5f1960f88560031b161c199101351690555f8080614b0b565b91936020600181928787013581550195019201614af5565b601f19831691845f5260205f20925f5b818110614b9c575092600192859261479998966002989610614b83575b505050811b01905561478d565b5f1960f88560031b161c199101351690555f8080614b76565b91936020600181928787013581550195019201614b59565b63ffffffff165f52600460205260405f2060ff815416600481101561115557600103614bdd5790565b7f8ca98990000000000000000000000000000000000000000000000000000000005f5260045ffd5b63ffffffff165f52600460205260405f2060ff815416600481101561115557600203614bdd5790565b614c9790600360ff19845416178355614c8a614c4c60208301614028565b84547fffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffff1660489190911b6cffffffff00000000000000000016178455565b6112a38361322883614028565b90547fdb439789af7a0ed4968cc1f35b0c7dfd9c878c6508bd7fd48053e87df31231d060405180614cfa63ffffffff808660081c1696169463ffffffff808260481c169160281c168390929163ffffffff60209181604085019616845216910152565b0390a3565b63ffffffff165f52600460205260405f205460ff8116600481101561115557600303614bdd5760081c63ffffffff1690565b90816020910312610584575180151581036105845790565b949192613e86969467ffffffffffffffff614d8f9563ffffffff614d819516895216602088015260a0604088015260a0870191614039565b908482036060860152613b85565b916080818403910152613b85565b5f90614df9602096949597614de2614dc66001600160a01b03614dbf86614e27565b1697615d2d565b91604051928a840152898352614ddd604084613d0c565b615d53565b90604051918983015288825261135b604083613d0c565b03925af1908115610588575f91614e0e575090565b613e86915060203d602011611576576115688183613d0c565b63ffffffff165f5260036020526001600160a01b0360405f2054168015614e4b5790565b7fb6c71f7d000000000000000000000000000000000000000000000000000000005f5260045ffd5b63ffffffff60019116019063ffffffff821161203b57565b7f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a5f525f60205263ffffffff60405f20541663ffffffff614ecb82614e73565b7f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a5f908152602052167f24072874bb11662934f0c68ca2659a14efae71555bb48eba2450fe6433183f955590565b90614f709060405163ffffffff602082019254614f398460ff8316613e89565b818160081c166040840152818160281c16606084015260481c16608082015260808152614f6760a082613d0c565b51902091615de0565b5f525f60205260405f2055565b7fc031b20c2b3a8a1fbfa9cc022aa3477489d4b8c91f0e667e900f5ad44daf8b6d5f525f60205263ffffffff60405f20541663ffffffff614fbd82614e73565b7fc031b20c2b3a8a1fbfa9cc022aa3477489d4b8c91f0e667e900f5ad44daf8b6d5f908152602052167fa948e29ac0e6a6a5e3c647a07a0505170c972dd4960cbe194aee77626bb52b585590565b906040519061501982613cd4565b80549160ff831660058110156111555761507b6150859363ffffffff614f70966002948652818160081c16602087015260281c16604085015260405161506681611c008160018601613c52565b6060850152611c006040518094819301613c52565b6080820152615d53565b91615d2d565b60405163ffffffff60208201925f8452166040820152604081526150b0606082613d0c565b51902090565b9067ffffffffffffffff6040519163ffffffff602084019460018652166040840152166060820152606081526150b0608082613d0c565b91939263ffffffff908161510b604094606087526060870190613c52565b9616602085015216910152565b9063ffffffff61512783614028565b165f52600560205260405f209160ff83541660058110156111555760010361112d57600360ff1984541617835560208101906151638282613f7e565b600286019167ffffffffffffffff821161060857615185826103118554613c01565b5f90601f83116001146152fd576151b192915f91836105935750505f198260011b9260031b1c19161790565b90555b6001600160a01b0360408201936152076151cd86614028565b87547fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff1660289190911b68ffffffff000000000016178755565b6152148661102485614028565b169261521f82614028565b9261523361522c83614028565b9184613f7e565b91909461524260a08601613f55565b92873b15610584575f936152859160405198899586957fa6071af900000000000000000000000000000000000000000000000000000000875233600488016140e4565b038183885af1918215610588576152d46152ce614cfa927f958d927ded58a29a450e24013886756bcee58e1146c05e9d0c671e5003cf8d909663ffffffff966152ed5750614028565b92614028565b83875460081c16906001604051958695169801846150ed565b5f6152f791613d0c565b5f612297565b601f19831691845f5260205f20925f5b8181106153495750908460019594939210615330575b505050811b0190556151b4565b5f1960f88560031b161c199101351690555f8080615323565b9193602060018192878701358155019501920161530d565b60405190816020810193806040830160208752526060820160608260051b84010191845f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301935b8383106153cc5750505050506150b0925003601f198101835282613d0c565b9193957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa09086929496030182528635868112156105845760206154146001938683940161429b565b980192019301909593918795936153ad565b80511561157d5760200190565b6040908151906154438383613d0c565b60018252601f1983015f5b8181106154fd57505061546082615426565b5261546a81615426565b508151908160208101938101916020855280518093526060820192602060608260051b8501019201935f905b8282106154b3575050506150b0925003601f198101835282613d0c565b919360206154ed857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0839460019698030186528851613eab565b9601920192018593919492615496565b602090615508614315565b8282870101520161544e565b6040516020810191600483526040820152604081526150b0606082613d0c565b60206001600160a01b037f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9216807fffffffffffffffffffffffff00000000000000000000000000000000000000007ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a005416177ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a0055604051908152a1565b6155ee90600360ff198454161783556112a38361322883614028565b90547fc382cf337d6f6a49bfb3fb8ec3fa62783704bd87aa72d534ff1b99195050aad860405180614cfa63ffffffff808660081c1696169463ffffffff808260481c169160281c168390929163ffffffff60209181604085019616845216910152565b6040516020810191600583526040820152604081526150b0606082613d0c565b9060408051926156818285613d0c565b60018452601f1982015f5b81811061578257505061569e84615426565b526156a883615426565b508051602081019181016020835284518091526060820190602060608260051b8501019601915f905b8282106157395750505050615710817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff949503601f198101835282613d0c565b519020167f01000000000000000000000000000000000000000000000000000000000000001790565b90919296602080615774837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa089600196030186528b51613b85565b9901920192019092916156d1565b80606060208093890101520161568c565b9190604051602081019180604083016020855252606082019060608160051b8401019580925f915b8383106157fb575050505050615710817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff949503601f198101835282613d0c565b9091929397602080615840837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08a6001960301875261583a8d8761424b565b90614039565b9a0193019301919392906157bb565b90916001600160a01b0390600360ff198554161784556158728461102485614028565b169061587d81614028565b61588960608301613f55565b90833b15610584576040517fce650d3900000000000000000000000000000000000000000000000000000000815233600482015263ffffffff9190911660248201526001600160a01b039190911660448201525f8160648183875af18015610588577f03c5f9b30a58d1ae49f1cff4d32c3906e7705104c0e815b97492af31137cb9fb9263ffffffff92615921926152ed5750614028565b614cfa85546040519384931696600163ffffffff808460081c169360281c169101846150ed565b63ffffffff165f52600560205260405f2060ff81541660058110156111555760030361112d5790565b63ffffffff165f5260066020526001600160a01b0360405f20541680156159955790565b7fc6830cff000000000000000000000000000000000000000000000000000000005f5260045ffd5b6138166114dd6159ce923690614196565b805f525f60205260405f20547f02000000000000000000000000000000000000000000000000000000000000008114615a55577f0100000000000000000000000000000000000000000000000000000000000000036126dc575f525f6020527f020000000000000000000000000000000000000000000000000000000000000060405f2055565b7f40862ab2000000000000000000000000000000000000000000000000000000005f5260045ffd5b90815f525f60205260405f20548015615af5577f010000000000000000000000000000000000000000000000000000000000000003615acd57615abf90615671565b905f525f60205260405f2055565b7f5c6d7711000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f53a55dcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f90614df9602096949597615b436001600160a01b03615b3c85614e27565b1696615de0565b906040519189830152888252615b5a604083613d0c565b60405163ffffffff60608b830193615b73858251613e89565b828d8201511660408501528260408201511682850152015116608082015260808152615ba060a082613d0c565b51902090604051918983015288825261135b604083613d0c565b615bc2614e8b565b9063ffffffff8216805f5260046020527f0a9d00e740d5a7292ecf25db89826a19ca7963a06c398a7f95947e84d1ce8f3163ffffffff60405f2093615d27615d04615cfe615cf860408501615c4f615c1982614028565b8b547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1660089190911b64ffffffff0016178b55565b600260ff198b5416178a55615ca0615c6687614028565b8b547fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff1660289190911b68ffffffff000000000016178b55565b6112a3602087019a615cf2615cb48d614028565b82547fffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffff1660489190911b6cffffffff00000000000000000016178255565b8c614f19565b93614028565b96614028565b60405193849316968390929163ffffffff60209181604085019616845216910152565b0390a390565b60405163ffffffff602082019260038452166040820152604081526150b0606082613d0c565b6040516150b0816148aa602082019460208652615d74604084018251613d2f565b63ffffffff602082015116606084015263ffffffff60408201511660808401526080615dae606083015160a08087015260e0860190613b85565b9101517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08483030160c0850152613b85565b60405163ffffffff602082019260028452166040820152604081526150b0606082613d0c565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615615e3557565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b90615e9a5750805115615e7257805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580615ee0575b615eab575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15615ea356f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00
Deployed Bytecode
0x60c06040526004361015610011575f80fd5b5f3560e01c80630d27062c14613b045780630e04968414613784578063113a1b70146136d55780631184fa02146136755780631296c1481461362257806317cad5cc146135f557806318c19870146134be5780632b2c54631461336657806336853d6d1461327957806343085db114613165578063441fd11514612d8b5780634f1ef28614612aa857806352d1902d14612a165780635501032e146129575780635f5d288e146129195780636415d1a3146127b5578063653c1b5e1461274157806378890388146125875780637a9e5e4b146124cc5780637fc254f41461249f57806381408dfd146122ad57806382a09c1514612091578063839df945146120685780638a65334614611d4d5780638fb3603714611cba578063990491a514611c4a578063999d5c6b14611ae75780639aa0346f1461175f5780639f18077b14611631578063ad3cb1cc146115d2578063afc3619b1461125c578063b1892e40146111f8578063b2b16d1c14611182578063b69562bd14610fba578063bf7e214f14610f75578063c4d66de814610cc7578063d36623ad14610c30578063d937c37914610c0e578063de844ebc14610bd0578063dea5a72314610ba1578063dee97dc6146109f4578063e1dc07c614610958578063e5cbff7914610727578063fb407dca1461065d5763fed12cbf14610208575f80fd5b346105845761021636613d6f565b6102203633614376565b6001600160a01b0360206102348380613f7e565b91908260405193849283378101600181520301902054168015610635577f9b9820486a05c0193efb214c6c2ba8fce02c5a5c84aa057f8199c99f13ff939b5f525f60205263ffffffff60405f2054169063ffffffff61029283614e73565b7f9b9820486a05c0193efb214c6c2ba8fce02c5a5c84aa057f8199c99f13ff939b5f908152602052167fa17c46f2d2a87aa05f956999001178d4f3a177d856047a83ccebd64d7a2ef49d556102e78380613f7e565b835f52600260205260405f209167ffffffffffffffff821161060857610317826103118554613c01565b85614095565b5f90601f831160011461059e578261040e95935f959361034b938792610593575b50505f198260011b9260031b1c19161790565b90555b8382526003602052604082206001600160a01b0382167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790556103986020860186613f7e565b838660606001600160a01b036104208b6103c46103bb6040839b9a9b0183613f7e565b95909201613f55565b936040519b8c9a8b998a987f384a3c30000000000000000000000000000000000000000000000000000000008a523360048b015260248a015260a060448a015260a4890191614039565b91600319878403016064880152614039565b9116608483015203925af1908115610588575f905f926104fb575b50907f03f4bda014b6bddaa31ba73f9e94f6bf6b7ba5b4f9c65b67640800c2b62964316020948385945161046e8661508b565b5f525f885260405f205561049467ffffffffffffffff60408984015193015116866150b6565b5f525f875260405f20556104b76104f06104ae8380613f7e565b92909380613f7e565b92909381604051928392833781015f8152039020946104e3604051948594604086526040860191614039565b908382038a850152613b85565b0390a3604051908152f35b9150503d805f833e61050d8183613d0c565b810190608081830312610584576105248282614135565b9060608101519067ffffffffffffffff821161058457019180601f840112156105845760209461057b7f03f4bda014b6bddaa31ba73f9e94f6bf6b7ba5b4f9c65b67640800c2b62964319285888897519101614340565b9350945061043b565b5f80fd5b6040513d5f823e3d90fd5b013590505f80610338565b601f19831691845f5260205f20925f5b8181106105f0575092600192859261040e98965f9896106105d7575b505050811b01905561034e565b5f1960f88560031b161c199101351690555f80806105ca565b919360206001819287870135815501950192016105ae565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7faa478af9000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105845761066b36613baa565b6106e161067782614028565b6106b56040840163ffffffff61068c82614028565b816040519561069a87613cf0565b600187521660208601521660408401525f6060840152614028565b6106c160808501613f69565b6106ce6060860186613f7e565b916106db60208801614028565b93615b1d565b156106ff576106f1602091615bba565b63ffffffff60405191168152f35b7f14209932000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461058457608060031936011261058457610740613bdd565b6024359067ffffffffffffffff82168092036105845760443567ffffffffffffffff81168091036105845760643567ffffffffffffffff81116105845761078b903690600401613da2565b9390610795614315565b5081610930578215610908576107c58463ffffffff165f5260066020526001600160a01b0360405f205416331490565b156108e0576108059063ffffffff6107dc86615948565b5460281c169563ffffffff604051966107f488613cd4565b169687875260208701523691613e35565b60408401526060830152608082015261081d81615433565b61082681615514565b92835f525f60205260405f20546108b8576108b4935f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f20557f635b5d234fe7abddfb29b6c8498780a3175c9002c537f20a3d1bf9d0e625b5fe604051602081528061089d6020820187613eab565b0390a3604051918291602083526020830190613eab565b0390f35b7fa29bd6ea000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fcc12cef6000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fddd92f79000000000000000000000000000000000000000000000000000000005f5260045ffd5b7faf2726eb000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105845761096636613dd0565b61097761097282614028565b614c05565b6109e4815463ffffffff8160081c1663ffffffff61099486614028565b9281604051946109a386613cf0565b60038652818360281c1660208701528460408701521660608501526109ca60408801613f69565b6109d76020890189613f7e565b93909260481c1693615b1d565b156106ff576109f2916155d2565b005b3461058457610a0236613dd0565b610a0c3633614376565b6001600160a01b03610a25610a2083614028565b614e27565b16906060610a3282614028565b92610a406020840184613f7e565b91905f610a4f60408701613f55565b96610a8a604051988996879586947f8f2a49300000000000000000000000000000000000000000000000000000000086523360048701614059565b03925af1918215610588575f92610b2c575b50602063ffffffff67ffffffffffffffff610b1d7f078276040a4f9f4dea1214e38413d6bac929b39330be19599176564d23d5ef41948651610ae5610ae083614028565b61508b565b5f525f865260405f205584870151610b0e6040610b0184614028565b990198858a5116906150b6565b5f525f865260405f2055614028565b945116936040519485521692a2005b90915060603d606011610b9a575b610b448183613d0c565b8101906060818303126105845763ffffffff67ffffffffffffffff610b1d610b8f7f078276040a4f9f4dea1214e38413d6bac929b39330be19599176564d23d5ef4195602095614135565b959450505050610a9c565b503d610b3a565b34610584576020600319360112610584576020610bbf610a20613bdd565b6001600160a01b0360405191168152f35b346105845760206003193601126105845763ffffffff610bee613bdd565b165f52600660205260206001600160a01b0360405f205416604051908152f35b346105845760206106f1610c2136613baa565b610c2b3633614376565b615bba565b3461058457610c3e36613d6f565b610c4f610c4a82614028565b614bb4565b610cb9815463ffffffff8160081c1663ffffffff610c6c86614028565b8160405194610c7a86613cf0565b6002865260281c166020850152826040850152166060830152610c9f60608601613f69565b610cac6040870187613f7e565b916106db60208901614028565b156106ff576109f291614c2e565b3461058457602060031936011261058457610ce0613e03565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c16159167ffffffffffffffff821680159081610f6d575b6001149081610f63575b159081610f5a575b50610f3257818360017fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000610da69516177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055610edd575b50610d91615e06565b610d99615e06565b610da1615e06565b615534565b610dae615e06565b5f602081905260017fa17c46f2d2a87aa05f956999001178d4f3a177d856047a83ccebd64d7a2ef49d8190557fa948e29ac0e6a6a5e3c647a07a0505170c972dd4960cbe194aee77626bb52b588190557f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a9091527f24072874bb11662934f0c68ca2659a14efae71555bb48eba2450fe6433183f9555610e4a57005b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005583610d88565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b90501584610d31565b303b159150610d29565b849150610d1f565b34610584575f6003193601126105845760206001600160a01b037ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a005416604051908152f35b346105845760406003193601126105845763ffffffff610fd8614002565b165f52600560205260405f20805460ff811660058110156111555760030361112d5763ffffffff61100c9160081c16614cff565b50600460ff1982541617815561102981611024614002565b61500b565b63ffffffff611036614002565b165f5260066020526001600160a01b0360405f205416611054614002565b602435906001600160a01b038216820361058457823b15610584576040517f172d9c4800000000000000000000000000000000000000000000000000000000815233600482015263ffffffff9190911660248201526001600160a01b039190911660448201525f8160648183865af180156105885761111d575b507f5d4b57424fd8ef7d85bed4d570d10b0bf5d38ef1936569ba4ca1f62ff78836e563ffffffff6110fd614002565b61111882865460281c1660016040519485941697018361422e565b0390a3005b5f61112791613d0c565b826110ce565b7f96d09146000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b346105845761119036613d6f565b61119a3633614376565b63ffffffff6111a882614028565b165f52600560205260405f209060ff82541660058110156111555760020361112d576109f29163ffffffff6111dc83614028565b165f5260066020526001600160a01b0360405f2054169161584f565b346105845760206003193601126105845763ffffffff611216613bdd565b165f526004602052608060405f205463ffffffff6040519161123b8360ff8316613e89565b818160081c166020840152818160281c16604084015260481c166060820152f35b346105845761126a36613baa565b6112743633614376565b61127e8180613f01565b80929150156115aa576112918180613f01565b1561157d576112a3816112a892613fcf565b614028565b906112c463ffffffff6112ba84615948565b5460081c16614cff565b9261139160206112e56112e06112da8680613f01565b90615361565b615651565b95818501966112fd6112f78988613f01565b90615793565b915f61130b60608901613f69565b9161131960408a018a613f7e565b9790956001600160a01b0361132d84614e27565b16956040519089820152888152611345604082613d0c565b604051918983015288825261135b604083613d0c565b604051998a98899788967fa9f9396e00000000000000000000000000000000000000000000000000000000885260048801614d49565b03925af1908115610588575f9161154e575b50156106ff57916113b381615971565b6001600160a01b031691608081019163ffffffff16905f5b8581106113d457005b6113e8816113e28480613f01565b9061417f565b908363ffffffff6113f884614028565b160361152657611407826159bd565b61141b816114158a86613f01565b90614213565b9061142587613f55565b93883b15610584575f6040518080977f2cd66b6f000000000000000000000000000000000000000000000000000000008252336004830152608060248301526001600160a01b0361148f61147c608485018861429b565b6003198582030160448601528989614039565b911660648301520381838d5af1908115610588576114e26114dd7f41d958a7d93b50b1f7541c6fc345d0c4657b1e83497baa562c866611ac1f69bb926001988b95611516575b503690614196565b615433565b926001600160a01b036114f48b613f55565b169461150d604051928392602084526020840191614039565b0390a4016113cb565b5f61152091613d0c565b8f6114d5565b7f9629d3d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b611570915060203d602011611576575b6115688183613d0c565b810190614d31565b856113a3565b503d61155e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f5458d343000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610584575f600319360112610584576108b46040516115f3604082613d0c565b600581527f352e302e300000000000000000000000000000000000000000000000000000006020820152604051918291602083526020830190613b85565b346105845760406003193601126105845760043567ffffffffffffffff81116105845760a060031982360301126105845760243567ffffffffffffffff811161058457611682903690600401613e6b565b8051156117375760248201916116ba61169a84614028565b63ffffffff165f5260066020526001600160a01b0360405f205416331490565b156108e05761111863ffffffff61172161170e6114dd7f488830ba53f27b7033e966a79427476ad47d550358e894bafeef8b97c6559251956117036116fe8a614028565b615948565b503690600401614196565b956112a38661171c89615651565b615a7d565b1692604051918291602083526020830190613b85565b7f2430f403000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105845761176d36613d6f565b6117773633614376565b6117818180613fcf565b61178a81614028565b9161179c63ffffffff6112ba85615948565b916001600160a01b036117ae84614e27565b169260408301604460206117c183613f69565b96604051928380927fe9946fc300000000000000000000000000000000000000000000000000000000825267ffffffffffffffff63ffffffff89169b8c60048501521660248301525afa8015610588575f90611aa6575b67ffffffffffffffff915016918215611a7e576118353685614196565b61183e90615433565b9561184887615651565b9261185290613f69565b906118606020880188613f7e565b94909361186c90614e27565b6001600160a01b0316936040519160208301526020825261188e604083613d0c565b60405195869485947f3fd413de000000000000000000000000000000000000000000000000000000008652600486015267ffffffffffffffff166024850152604484016080905260848401906118e392614039565b8281036003190160648401526118f891613b85565b03815a6020945f91f1908115610588575f91611a5f575b50156106ff5761191e85615971565b90611928836159bd565b6080830167ffffffffffffffff61193e82613f69565b16156109085761195667ffffffffffffffff91613f69565b1611611a37576001600160a01b036060911692019161197483613f55565b91813b15610584575f916119cf836001600160a01b0393604051968795869485937f168ce11c00000000000000000000000000000000000000000000000000000000855233600486015260606024860152606485019061429b565b9116604483015203925af180156105885763ffffffff926001600160a01b03926119fe92611a27575b50613f55565b1692167f34df62ed9d26dbe71f13d2bd3f645d6cd16b0c44645ef783c2ed799748c80a745f80a4005b5f611a3191613d0c565b866119f8565b7f8551d235000000000000000000000000000000000000000000000000000000005f5260045ffd5b611a78915060203d602011611576576115688183613d0c565b8661190f565b7f9b6c9adc000000000000000000000000000000000000000000000000000000005f5260045ffd5b506020813d602011611adf575b81611ac060209383613d0c565b8101031261058457611ada67ffffffffffffffff91614120565b611818565b3d9150611ab3565b3461058457611af536613d6f565b63ffffffff611b0382614028565b165f52600560205260405f209081549160ff831660058110156111555760020361112d57611c3263ffffffff8460081c16611b3d81614cff565b63ffffffff611b4b86614028565b165f52600660205263ffffffff60405f205496611b89611b6a88614028565b9463ffffffff165f52600460205263ffffffff60405f205460481c1690565b9382604051917fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008b60601b16602084015260148352611bc9603484613d0c565b8160405197611bd789613cd4565b600389521660208801521660408601526060850152604051611c0781611c008160028b01613c52565b0382613d0c565b6080850152611c1860408801613f69565b611c256020890189613f7e565b93909260281c1693614d9d565b156106ff576001600160a01b036109f293169161584f565b346105845760206003193601126105845760043567ffffffffffffffff81116105845736602382011215610584576001600160a01b03602080611c9881943690602481600401359101613e35565b604051928184925191829101835e810160018152030190205416604051908152f35b34610584575f600319360112610584577ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a005460a01c60ff1615611d455760207f8fb36037000000000000000000000000000000000000000000000000000000005b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b60205f611d1b565b3461058457611d8e611d5e36613dd0565b611d683633614376565b611d728180613f01565b929091611d8160408201613f55565b6080526020810190613f01565b9083156115aa57611daa6020611da48580613fcf565b01614028565b93611dbc63ffffffff6112ba87615948565b50611dc685615971565b5f633b9aca0042029267ffffffffffffffff428504633b9aca0014421517159416915b818110611df257005b611dfd81838a61417f565b90602082019163ffffffff8b1663ffffffff611e1885614028565b16036115265767ffffffffffffffff611e3360608301613f69565b16610930578661203b5767ffffffffffffffff611e5260808301613f69565b1685101561201357611e676114dd3683614196565b90611e7182615651565b90815f525f602052878b8b60405f20541580611fe1575b611e9d575b5050505050506001915001611de9565b6001600160a01b039793611ef99593611eb9895f958695614213565b94819b86946040519a8b96879586937f6f104830000000000000000000000000000000000000000000000000000000008552608051903360048701614618565b0393165af19384156105885760019786915f96611fbd575b507fdbb36eab1a905641d6490533e8dfb257a8633c9a26a166c0954a1fc59d7946b7611f6763ffffffff611f4488614028565b1692604051918291602083526001600160a01b0360805116976020840191614039565b0390a48251611f7a575b50878b8b611e8d565b63ffffffff6117217f488830ba53f27b7033e966a79427476ad47d550358e894bafeef8b97c6559251936112a386611fb195615a7d565b0390a38a808080611f71565b611fda9196503d805f833e611fd28183613d0c565b8101906145e1565b945f611f11565b855f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f2055611e88565b7fa4821270000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b34610584576020600319360112610584576004355f525f602052602060405f2054604051908152f35b346105845761209f36613d6f565b63ffffffff6120ad82614028565b165f52600560205260405f209081549060ff821660058110156111555760030361112d576121d263ffffffff8360081c166120e781614cff565b63ffffffff6120f585614028565b165f52600660205263ffffffff60405f2054956001600160a01b038716968261213f61212089614028565b9663ffffffff165f52600460205263ffffffff60405f205460481c1690565b957fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519360601b1660208401526014835261217d603484613d0c565b816040519761218b89613cd4565b6004895216602088015216604086015260608501526040516121b481611c008160028d01613c52565b60808501526121c560408701613f69565b611c256020880188613f7e565b156106ff57600460ff198454161783556121ef8361102483614028565b6121f881614028565b61220460608301613f55565b90833b15610584576040517f40380c6100000000000000000000000000000000000000000000000000000000815233600482015263ffffffff9190911660248201526001600160a01b039190911660448201525f8160648183875af18015610588577ff55ea0b61aba75ba1463c3325f7b0a06baa2d96ee4a621a05dabdf03b489c41d9263ffffffff926110fd9261229d575b50614028565b5f6122a791613d0c565b86612297565b346105845760206003193601126105845760043567ffffffffffffffff811161058457806004019060406003198236030112610584576122ed3633614376565b6122f78280613f01565b919050600282106115aa5761230c8380613f01565b1561157d576020611da48261232093613fcf565b9161232e6112da8580613f01565b602463ffffffff5f95169301935b82811061237057856123616112e06112da61235a6112f78a86613f01565b9380613f01565b5f525f60205260405f20555f80f35b61237e816113e28880613f01565b908061245f575b6114dd6123a3612399836114158a8c613f01565b9290943690614196565b926123ad84615651565b5f525f60205260405f20549182158015612436575b611737576123da916123d5913691613e35565b615671565b0361240e5760019183867fdf2b8ea755edd621da990db5273e5ac28efcd0462a19552a690540f9ef63b14f5f80a40161233c565b7f59c3580a000000000000000000000000000000000000000000000000000000005f5260045ffd5b507f010000000000000000000000000000000000000000000000000000000000000083146123c2565b8463ffffffff61247160208501614028565b1614612385577f9629d3d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610584576109f26124b036613dd0565b6124ba3633614376565b6124c661097282614028565b906155d2565b34610584576020600319360112610584576124e5613e03565b6001600160a01b037ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a005416330361255b57803b15612526576109f290615534565b6001600160a01b03907fc2f31e5e000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b7f068ca9d8000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b346105845760206003193601126105845760043567ffffffffffffffff8111610584576020600319826004019236030112610584576125c63633614376565b6125d08180613f01565b919050600282106115aa576125e58180613f01565b1561157d576112a3816125f792613fcf565b916126056112da8380613f01565b9163ffffffff5f9416935b8281106126505761262084615514565b5f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f20555f80f35b61265e816113e28480613f01565b81612704575b6114dd612672913690614196565b9061267c82615514565b5f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f2054036126dc5760019185877f8ffe8d45aea2ea970a08903423957c59d26de1fb69c2928b63562c13ccd5e3cb5f80a401612610565b7f4d7cfc57000000000000000000000000000000000000000000000000000000005f5260045ffd5b8563ffffffff61271383614028565b1614612664577f9629d3d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105845761274f36613d3c565b6127593633614376565b63ffffffff61276782614028565b165f52600560205260ff60405f20541660058110156111555760010361112d578063ffffffff6127996109f293614028565b165f5260066020526001600160a01b0360405f20541690615118565b34610584576127c336613d3c565b63ffffffff6127d182614028565b165f52600560205260405f205460ff811660058110156111555760010361112d5760081c63ffffffff169061290161280883614cff565b9263ffffffff61281784614028565b165f52600660205260405f2054936128d061285361283486614028565b9363ffffffff165f52600460205263ffffffff60405f205460481c1690565b9263ffffffff6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008960601b16602082015260148152612896603482613d0c565b6128a36020890189613f7e565b92909381604051986128b48a613cd4565b60028a5216602089015216604087015260608601523691613e35565b60808301526128e160808501613f69565b6128ee6060860186613f7e565b916128fb60408801614028565b93614d9d565b156106ff576001600160a01b036109f2921690615118565b346105845760206003193601126105845763ffffffff612937613bdd565b165f52600360205260206001600160a01b0360405f205416604051908152f35b346105845761296536613dd0565b61296f3633614376565b6001600160a01b03612983610a2083614028565b169060605f61299183614028565b9363ffffffff6129a46020860186613f7e565b939096610a8a6129b76040890189613f7e565b612a046040519b8c998a9889977f446005b80000000000000000000000000000000000000000000000000000000089523360048a0152166024880152608060448801526084870191614039565b91600319858403016064860152614039565b34610584575f600319360112610584576001600160a01b037f0000000000000000000000000a25207f368d04de034618dad79e768f35c62309163003612a805760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b7fe07c8dba000000000000000000000000000000000000000000000000000000005f5260045ffd5b604060031936011261058457612abc613e03565b60243567ffffffffffffffff811161058457612adc903690600401613e6b565b6001600160a01b037f0000000000000000000000000a25207f368d04de034618dad79e768f35c6230916803014908115612d56575b50612a8057612b203633614376565b6001600160a01b038216916040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481875afa5f9181612d22575b50612b9357837f4c9c8ce3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc859203612cf75750813b15612ccc57807fffffffffffffffffffffffff00000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2815115612c9b575f808360206109f295519101845af43d15612c93573d91612c7783613e19565b92612c856040519485613d0c565b83523d5f602085013e615e5d565b606091615e5d565b505034612ca457005b7fb398979f000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4c9c8ce3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7faa1d49a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091506020813d602011612d4e575b81612d3e60209383613d0c565b8101031261058457519085612b62565b3d9150612d31565b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416141583612b11565b3461058457612d9936613baa565b60408101612dae612da982614028565b614cff565b50612db7614f7d565b9063ffffffff821691825f52600560205260405f2093600160ff19865416178555612e1a612de484614028565b86547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1660089190911b64ffffffff0016178655565b60608101612e288183613f7e565b600288019167ffffffffffffffff821161060857612e4a826103118554613c01565b5f90601f831160011461310157612e7692915f91836130f65750505f198260011b9260031b1c19161790565b90555b612e866020830183613f7e565b60018801979167ffffffffffffffff821161060857612eaf82612ea98b54613c01565b8b614095565b5f90601f831160011461308e579180612ee092612ee995945f926130835750505f198260011b9260031b1c19161790565b88555b8461500b565b612f3b83612ef684613f55565b9063ffffffff165f5260066020526001600160a01b0360405f2091167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6001600160a01b03612f4c83613f55565b1692612f5785614028565b90612f628385613f7e565b959091612f7160808701613f55565b823b15610584575f94612fb686926040519a8b97889687957f10cac64800000000000000000000000000000000000000000000000000000000875233600488016140e4565b03925af1928315610588576020966130687f370d54a331c7da62dbd4e3f464f8ca9b0c4726640604fcb08cd4cfb5ed41d03393613053938997613073575b5061300761300187613f55565b98614028565b906001600160a01b0361302561301d838a613f7e565b939099613f7e565b92909881604051928392833781015f81520390209963ffffffff604051978897606089526060890190613c52565b94168d87015285840360408701521696614039565b0390a4604051908152f35b5f61307d91613d0c565b8a612ff4565b013590508b80610338565b601f198316918a5f5260205f20925f5b8181106130de5750916001939185612ee9979694106130c5575b505050811b018855612ee3565b5f1960f88560031b161c199101351690558a80806130b8565b9193602060018192878701358155019501920161309e565b013590508a80610338565b601f19831691845f5260205f20925f5b81811061314d5750908460019594939210613134575b505050811b019055612e79565b5f1960f88560031b161c19910135169055898080613127565b91936020600181928787013581550195019201613111565b34610584576040600319360112610584576020613180614e8b565b61322d63ffffffff821691825f526004845260405f20906131d86131a2614002565b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1660089190911b64ffffffff0016178355565b600160ff198354161782556132286131ee614015565b83547fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff1660289190911b68ffffffff000000000016178355565b614f19565b613235614002565b817f5c19396f17b2d5b8ebfa9d37569101115f64e85557fe202593aa3e5555bad05d8463ffffffff613265614015565b9481604051961686521693a3604051908152f35b346105845761328736613dd0565b6132913633614376565b6001600160a01b036132a5610a2083614028565b16906132b081614028565b6132bd6020830183613f7e565b90936132cb60408501613f55565b94813b15610584575f8094613310604051988996879586947f553931740000000000000000000000000000000000000000000000000000000086523360048701614059565b03925af19081156105885763ffffffff9261332f926133565750614028565b167f2d86933ea68552f2484167a027c9e1a658fee909dffcc151fb2d4fde750311265f80a2005b5f61336091613d0c565b83612297565b346105845761337436613d3c565b602081016133828183613fcf565b356005811015610584577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0161112d57806133c8612da96020611da46134ae9587613fcf565b611da46133fb6133dd6020611da48689613fcf565b63ffffffff165f52600460205263ffffffff60405f205460481c1690565b9261348261340887613f55565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519160601b16602082015260148152613445603482613d0c565b6134526040890189613f7e565b909163ffffffff604051986134668a613cd4565b60018a521660208901525f604089015260608801523691613e35565b608085015261349360808701613f69565b6128fb60406134a560608a018a613f7e565b9590948a613fcf565b156106ff576106f1602091614655565b346105845760406003193601126105845760043567ffffffffffffffff8111610584576134ef903690600401613da2565b602435916001600160a01b0383168093036105845761350e3633614376565b6001600160a01b0360405183838237602081858101600181520301902054166135cd577f52dcd9fec0aa3ec676cc46ae22674ebc00b38c2e1c522b26910c5bdd76a3473c916040518183823760208183810160018152030190206001600160a01b0385167fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905560405181838237808281015f8152039020936135c2604051938493604085526040850191614039565b9060208301520390a2005b7f0c7cc9b9000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610584576109f261360636613d6f565b6136103633614376565b61361c610c4a82614028565b90614c2e565b346105845760206003193601126105845763ffffffff613640613bdd565b165f5260026020526108b4611c0061366160405f2060405192838092613c52565b604051918291602083526020830190613b85565b346105845761368336613d3c565b61368d3633614376565b61369a6020820182613fcf565b356005811015610584577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0161112d576106f1602091614655565b346105845760206003193601126105845763ffffffff6136f3613bdd565b165f52600560205263ffffffff60405f206108b4600261377683549361373e6040519161372e836137278160018501613c52565b0384613d0c565b6137276040518096819301613c52565b60405195856137518860ff819916613d2f565b818160081c16602088015260281c16604086015260a0606086015260a0850190613b85565b908382036080850152613b85565b346105845761379236613baa565b61379c3633614376565b6137a68180613f01565b6137b260408401613f55565b60a0526137c26020840184613f01565b916137dd6137d260808701613f69565b956060810190613f7e565b9082156115aa576020906137f582611da48980613fcf565b9761380763ffffffff6112ba8b615948565b905f61381b613816888c615361565b615514565b9261387f6001600160a01b0361383083614e27565b16946040519088820152878152613848604082613d0c565b604051907f01000000000000000000000000000000000000000000000000000000000000008983015288825261135b604083613d0c565b03925af1908115610588575f91613ae5575b50156106ff576138a085615971565b5f633b9aca0042029267ffffffffffffffff428504633b9aca0014421517159416915b8181106138cc57005b6138d781838a61417f565b90602082019163ffffffff8b1663ffffffff6138f285614028565b16036115265767ffffffffffffffff61390d60608301613f69565b16610930578661203b5767ffffffffffffffff61392c60808301613f69565b16851015612013576139416114dd3683614196565b9061394b82615651565b90815f525f602052878b8b60405f20541580613ab3575b613977575b50505050505060019150016138c3565b6001600160a01b0397936139d39593613993895f958695614213565b94819b86946040519a8b96879586937f667b822e00000000000000000000000000000000000000000000000000000000855260a051903360048701614618565b0393165af19384156105885760019786915f96613a97575b507fe450e03249d131499e278eeafd8e27effcceeb40b0b95628a087aa16b4b101d5613a4163ffffffff613a1e88614028565b1692604051918291602083526001600160a01b0360a05116976020840191614039565b0390a48251613a54575b50878b8b613967565b63ffffffff6117217f488830ba53f27b7033e966a79427476ad47d550358e894bafeef8b97c6559251936112a386613a8b95615a7d565b0390a38a808080613a4b565b613aac9196503d805f833e611fd28183613d0c565b945f6139eb565b855f525f6020527f010000000000000000000000000000000000000000000000000000000000000060405f2055613962565b613afe915060203d602011611576576115688183613d0c565b86613891565b34610584575f600319360112610584576108b4604051613b25606082613d0c565b602881527f373131336632363631303235383033303231663831396164643039393935666360208201527f653266353861626600000000000000000000000000000000000000000000000060408201526040519182916020835260208301905b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b6020600319820112610584576004359067ffffffffffffffff8211610584576003198260a0920301126105845760040190565b6004359063ffffffff8216820361058457565b359063ffffffff8216820361058457565b90600182811c92168015613c48575b6020831014613c1b57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691613c10565b5f9291815491613c6183613c01565b8083529260018116908115613cb65750600114613c7d57505050565b5f9081526020812093945091925b838310613c9c575060209250010190565b600181602092949394548385870101520191019190613c8b565b9050602094955060ff1991509291921683830152151560051b010190565b60a0810190811067ffffffffffffffff82111761060857604052565b6080810190811067ffffffffffffffff82111761060857604052565b90601f601f19910116810190811067ffffffffffffffff82111761060857604052565b9060058210156111555752565b6020600319820112610584576004359067ffffffffffffffff8211610584576003198260c0920301126105845760040190565b6020600319820112610584576004359067ffffffffffffffff821161058457600319826080920301126105845760040190565b9181601f840112156105845782359167ffffffffffffffff8311610584576020838186019501011161058457565b6020600319820112610584576004359067ffffffffffffffff821161058457600319826060920301126105845760040190565b600435906001600160a01b038216820361058457565b67ffffffffffffffff811161060857601f01601f191660200190565b929192613e4182613e19565b91613e4f6040519384613d0c565b829481845281830111610584578281602093845f960137010152565b9080601f8301121561058457816020613e8693359101613e35565b90565b9060048210156111555752565b359067ffffffffffffffff8216820361058457565b9063ffffffff825116815263ffffffff6020830151166020820152608067ffffffffffffffff81613eeb604086015160a0604087015260a0860190613b85565b9482606082015116606086015201511691015290565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610584570180359067ffffffffffffffff821161058457602001918160051b3603831361058457565b356001600160a01b03811681036105845790565b3567ffffffffffffffff811681036105845790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610584570180359067ffffffffffffffff82116105845760200191813603831361058457565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301821215610584570190565b60043563ffffffff811681036105845790565b60243563ffffffff811681036105845790565b3563ffffffff811681036105845790565b601f8260209493601f1993818652868601375f8582860101520116010190565b939260609363ffffffff6001600160a01b03948561408e959a999a168852166020870152608060408701526080860191614039565b9416910152565b601f82116140a257505050565b5f5260205f20906020601f840160051c830193106140da575b601f0160051c01905b8181106140cf575050565b5f81556001016140c4565b90915081906140bb565b9463ffffffff6001600160a01b03948161408e9587608099969c9b9c168a5216602089015216604087015260a0606087015260a0860191614039565b519067ffffffffffffffff8216820361058457565b9190826060910312610584576040516060810181811067ffffffffffffffff82111761060857604052604061417a818395805185526020810151602086015201614120565b910152565b9082101561157d57613e869160051b810190613fcf565b91909160a08184031261058457604051906141b082613cd4565b81936141bb82613bf0565b83526141c960208301613bf0565b602084015260408201359067ffffffffffffffff821161058457826141f76080949261417a94869401613e6b565b604086015261420860608201613e96565b606086015201613e96565b9082101561157d5761422a9160051b810190613f7e565b9091565b9063ffffffff61408e602092959495604085526040850190613c52565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561058457016020813591019167ffffffffffffffff821161058457813603831361058457565b9063ffffffff6142aa83613bf0565b16815263ffffffff6142be60208401613bf0565b166020820152608067ffffffffffffffff61430e826142f46142e3604088018861424b565b60a0604089015260a0880191614039565b958361430260608301613e96565b16606087015201613e96565b1691015290565b6040519061432282613cd4565b5f608083828152826020820152606060408201528260608201520152565b92919261434c82613e19565b9161435a6040519384613d0c565b829481845281830111610584578281602093845f96015e010152565b7ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a0054916001600160a01b0383169281600411610584575f5f9060405f8151966001600160a01b0360208901917fb700961300000000000000000000000000000000000000000000000000000000835216978860248201523060448201527fffffffff0000000000000000000000000000000000000000000000000000000083351660648201526064815261442b608482613d0c565b828052826020525190895afa6145ce575b15614449575b5050505050565b63ffffffff16156145a2577fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000177ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a0055823b15610584576020925f92836040518096819582947f94c7d7ee000000000000000000000000000000000000000000000000000000008452600484015260406024840152601f19601f6044850192808452808786860137868582860101520116010103925af1801561058857614592575b507fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff7ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a0054167ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a00555f80808080614442565b5f61459c91613d0c565b5f614521565b827f068ca9d8000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50505f516020518060201c15029061443c565b6020818303126105845780519067ffffffffffffffff821161058457019080601f83011215610584578151613e8692602001614340565b90614641613e86969495936001600160a01b03809316845260806020850152608084019061429b565b941660408201526060818503910152614039565b61465d614f7d565b906020810161466c8183613fcf565b9063ffffffff841691825f52600560205260405f20813560058110156105845760ff60ff1983541691161781556146de6146a860208401614028565b82547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1660089190911b64ffffffff0016178255565b6147276146ed60408401614028565b82547fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff1660289190911b68ffffffff000000000016178255565b600181016147386060840184613f7e565b9067ffffffffffffffff821161060857614756826103118554613c01565b5f90601f8311600114614b49578261479995936002959361478a935f926105935750505f198260011b9260031b1c19161790565b90555b01916080810190613f7e565b9067ffffffffffffffff8211610608576147b7826103118554613c01565b5f90601f8311600114614ae5576147e392915f91836105935750505f198260011b9260031b1c19161790565b90555b6147f08184613fcf565b6040516020810191602083528035906005821015610584576148aa839161481e6148b8946040850190613d2f565b63ffffffff61482f60208301613bf0565b16606084015263ffffffff61484660408301613bf0565b16608084015261487a61486f61485f606084018461424b565b60a08088015260e0870191614039565b91608081019061424b565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030160c0860152614039565b03601f198101835282613d0c565b5190206148c485615d2d565b5f525f60205260405f20556148dc84612ef685613f55565b6001600160a01b036148ed84613f55565b16906148fe6020611da48387613fcf565b9161490e6040611da48488613fcf565b9061492661491c8488613fcf565b6080810190613f7e565b9290946040880195614938878a613f7e565b61494460a08c01613f55565b92863b156105845760405197889687967f5101edc400000000000000000000000000000000000000000000000000000000885233600489015263ffffffff1660248801528c604488015263ffffffff1660648701526084860160e0905260e48601906149af92614039565b908482036003190160a48601526149c592614039565b906001600160a01b031660c483015203815a5f948591f1801561058857614ad5575b506149f184613f55565b936149fc8282613fcf565b60608101614a0991613f7e565b919092614a168183613fcf565b604001614a2290614028565b90614a2d9083613fcf565b602001614a3990614028565b96614a448684613f7e565b96614a4f9194613f7e565b96909381604051928392833781015f815203902097604051958695608087526080870190614a7c92614039565b9263ffffffff16602086015263ffffffff16604085015283820360608501526001600160a01b031694614aae92614039565b037f9856c775e40c73b8fdab7ee177e147e26a1ee9cda934ab9497a46da9ab5481ce91a490565b5f614adf91613d0c565b5f6149e7565b601f19831691845f5260205f20925f5b818110614b315750908460019594939210614b18575b505050811b0190556147e6565b5f1960f88560031b161c199101351690555f8080614b0b565b91936020600181928787013581550195019201614af5565b601f19831691845f5260205f20925f5b818110614b9c575092600192859261479998966002989610614b83575b505050811b01905561478d565b5f1960f88560031b161c199101351690555f8080614b76565b91936020600181928787013581550195019201614b59565b63ffffffff165f52600460205260405f2060ff815416600481101561115557600103614bdd5790565b7f8ca98990000000000000000000000000000000000000000000000000000000005f5260045ffd5b63ffffffff165f52600460205260405f2060ff815416600481101561115557600203614bdd5790565b614c9790600360ff19845416178355614c8a614c4c60208301614028565b84547fffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffff1660489190911b6cffffffff00000000000000000016178455565b6112a38361322883614028565b90547fdb439789af7a0ed4968cc1f35b0c7dfd9c878c6508bd7fd48053e87df31231d060405180614cfa63ffffffff808660081c1696169463ffffffff808260481c169160281c168390929163ffffffff60209181604085019616845216910152565b0390a3565b63ffffffff165f52600460205260405f205460ff8116600481101561115557600303614bdd5760081c63ffffffff1690565b90816020910312610584575180151581036105845790565b949192613e86969467ffffffffffffffff614d8f9563ffffffff614d819516895216602088015260a0604088015260a0870191614039565b908482036060860152613b85565b916080818403910152613b85565b5f90614df9602096949597614de2614dc66001600160a01b03614dbf86614e27565b1697615d2d565b91604051928a840152898352614ddd604084613d0c565b615d53565b90604051918983015288825261135b604083613d0c565b03925af1908115610588575f91614e0e575090565b613e86915060203d602011611576576115688183613d0c565b63ffffffff165f5260036020526001600160a01b0360405f2054168015614e4b5790565b7fb6c71f7d000000000000000000000000000000000000000000000000000000005f5260045ffd5b63ffffffff60019116019063ffffffff821161203b57565b7f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a5f525f60205263ffffffff60405f20541663ffffffff614ecb82614e73565b7f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a5f908152602052167f24072874bb11662934f0c68ca2659a14efae71555bb48eba2450fe6433183f955590565b90614f709060405163ffffffff602082019254614f398460ff8316613e89565b818160081c166040840152818160281c16606084015260481c16608082015260808152614f6760a082613d0c565b51902091615de0565b5f525f60205260405f2055565b7fc031b20c2b3a8a1fbfa9cc022aa3477489d4b8c91f0e667e900f5ad44daf8b6d5f525f60205263ffffffff60405f20541663ffffffff614fbd82614e73565b7fc031b20c2b3a8a1fbfa9cc022aa3477489d4b8c91f0e667e900f5ad44daf8b6d5f908152602052167fa948e29ac0e6a6a5e3c647a07a0505170c972dd4960cbe194aee77626bb52b585590565b906040519061501982613cd4565b80549160ff831660058110156111555761507b6150859363ffffffff614f70966002948652818160081c16602087015260281c16604085015260405161506681611c008160018601613c52565b6060850152611c006040518094819301613c52565b6080820152615d53565b91615d2d565b60405163ffffffff60208201925f8452166040820152604081526150b0606082613d0c565b51902090565b9067ffffffffffffffff6040519163ffffffff602084019460018652166040840152166060820152606081526150b0608082613d0c565b91939263ffffffff908161510b604094606087526060870190613c52565b9616602085015216910152565b9063ffffffff61512783614028565b165f52600560205260405f209160ff83541660058110156111555760010361112d57600360ff1984541617835560208101906151638282613f7e565b600286019167ffffffffffffffff821161060857615185826103118554613c01565b5f90601f83116001146152fd576151b192915f91836105935750505f198260011b9260031b1c19161790565b90555b6001600160a01b0360408201936152076151cd86614028565b87547fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff1660289190911b68ffffffff000000000016178755565b6152148661102485614028565b169261521f82614028565b9261523361522c83614028565b9184613f7e565b91909461524260a08601613f55565b92873b15610584575f936152859160405198899586957fa6071af900000000000000000000000000000000000000000000000000000000875233600488016140e4565b038183885af1918215610588576152d46152ce614cfa927f958d927ded58a29a450e24013886756bcee58e1146c05e9d0c671e5003cf8d909663ffffffff966152ed5750614028565b92614028565b83875460081c16906001604051958695169801846150ed565b5f6152f791613d0c565b5f612297565b601f19831691845f5260205f20925f5b8181106153495750908460019594939210615330575b505050811b0190556151b4565b5f1960f88560031b161c199101351690555f8080615323565b9193602060018192878701358155019501920161530d565b60405190816020810193806040830160208752526060820160608260051b84010191845f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301935b8383106153cc5750505050506150b0925003601f198101835282613d0c565b9193957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa09086929496030182528635868112156105845760206154146001938683940161429b565b980192019301909593918795936153ad565b80511561157d5760200190565b6040908151906154438383613d0c565b60018252601f1983015f5b8181106154fd57505061546082615426565b5261546a81615426565b508151908160208101938101916020855280518093526060820192602060608260051b8501019201935f905b8282106154b3575050506150b0925003601f198101835282613d0c565b919360206154ed857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0839460019698030186528851613eab565b9601920192018593919492615496565b602090615508614315565b8282870101520161544e565b6040516020810191600483526040820152604081526150b0606082613d0c565b60206001600160a01b037f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9216807fffffffffffffffffffffffff00000000000000000000000000000000000000007ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a005416177ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a0055604051908152a1565b6155ee90600360ff198454161783556112a38361322883614028565b90547fc382cf337d6f6a49bfb3fb8ec3fa62783704bd87aa72d534ff1b99195050aad860405180614cfa63ffffffff808660081c1696169463ffffffff808260481c169160281c168390929163ffffffff60209181604085019616845216910152565b6040516020810191600583526040820152604081526150b0606082613d0c565b9060408051926156818285613d0c565b60018452601f1982015f5b81811061578257505061569e84615426565b526156a883615426565b508051602081019181016020835284518091526060820190602060608260051b8501019601915f905b8282106157395750505050615710817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff949503601f198101835282613d0c565b519020167f01000000000000000000000000000000000000000000000000000000000000001790565b90919296602080615774837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa089600196030186528b51613b85565b9901920192019092916156d1565b80606060208093890101520161568c565b9190604051602081019180604083016020855252606082019060608160051b8401019580925f915b8383106157fb575050505050615710817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff949503601f198101835282613d0c565b9091929397602080615840837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08a6001960301875261583a8d8761424b565b90614039565b9a0193019301919392906157bb565b90916001600160a01b0390600360ff198554161784556158728461102485614028565b169061587d81614028565b61588960608301613f55565b90833b15610584576040517fce650d3900000000000000000000000000000000000000000000000000000000815233600482015263ffffffff9190911660248201526001600160a01b039190911660448201525f8160648183875af18015610588577f03c5f9b30a58d1ae49f1cff4d32c3906e7705104c0e815b97492af31137cb9fb9263ffffffff92615921926152ed5750614028565b614cfa85546040519384931696600163ffffffff808460081c169360281c169101846150ed565b63ffffffff165f52600560205260405f2060ff81541660058110156111555760030361112d5790565b63ffffffff165f5260066020526001600160a01b0360405f20541680156159955790565b7fc6830cff000000000000000000000000000000000000000000000000000000005f5260045ffd5b6138166114dd6159ce923690614196565b805f525f60205260405f20547f02000000000000000000000000000000000000000000000000000000000000008114615a55577f0100000000000000000000000000000000000000000000000000000000000000036126dc575f525f6020527f020000000000000000000000000000000000000000000000000000000000000060405f2055565b7f40862ab2000000000000000000000000000000000000000000000000000000005f5260045ffd5b90815f525f60205260405f20548015615af5577f010000000000000000000000000000000000000000000000000000000000000003615acd57615abf90615671565b905f525f60205260405f2055565b7f5c6d7711000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f53a55dcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f90614df9602096949597615b436001600160a01b03615b3c85614e27565b1696615de0565b906040519189830152888252615b5a604083613d0c565b60405163ffffffff60608b830193615b73858251613e89565b828d8201511660408501528260408201511682850152015116608082015260808152615ba060a082613d0c565b51902090604051918983015288825261135b604083613d0c565b615bc2614e8b565b9063ffffffff8216805f5260046020527f0a9d00e740d5a7292ecf25db89826a19ca7963a06c398a7f95947e84d1ce8f3163ffffffff60405f2093615d27615d04615cfe615cf860408501615c4f615c1982614028565b8b547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1660089190911b64ffffffff0016178b55565b600260ff198b5416178a55615ca0615c6687614028565b8b547fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff1660289190911b68ffffffff000000000016178b55565b6112a3602087019a615cf2615cb48d614028565b82547fffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffff1660489190911b6cffffffff00000000000000000016178255565b8c614f19565b93614028565b96614028565b60405193849316968390929163ffffffff60209181604085019616845216910152565b0390a390565b60405163ffffffff602082019260038452166040820152604081526150b0606082613d0c565b6040516150b0816148aa602082019460208652615d74604084018251613d2f565b63ffffffff602082015116606084015263ffffffff60408201511660808401526080615dae606083015160a08087015260e0860190613b85565b9101517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08483030160c0850152613b85565b60405163ffffffff602082019260028452166040820152604081526150b0606082613d0c565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615615e3557565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b90615e9a5750805115615e7257805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580615ee0575b615eab575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15615ea356
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.