Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
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:
OwnableIBCHandler
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 1000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.8.27;
import "./25-handler/IBCHandler.sol";
/**
* @dev OwnableIBCHandler is a contract that implements [ICS-25](https://github.com/cosmos/ibc/tree/main/spec/core/ics-025-handler-interface).
*/
contract OwnableIBCHandler is IBCHandler {
constructor() {
_disableInitializers();
}
function initialize(
address admin
) public override initializer {
IBCHandler.initialize(admin);
}
}pragma solidity ^0.8.27;
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 "@openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin-upgradeable/utils/ContextUpgradeable.sol";
import "@openzeppelin/utils/Context.sol";
/**
* @dev IBCHandler is a contract that implements [ICS-25](https://github.com/cosmos/ibc/tree/main/spec/core/ics-025-handler-interface).
*/
abstract contract IBCHandler is
Initializable,
UUPSUpgradeable,
OwnableUpgradeable,
IBCStore,
IBCClient,
IBCConnectionImpl,
IBCChannelImpl,
IBCPacketImpl
{
constructor() {
_disableInitializers();
}
function initialize(
address admin
) public virtual initializer {
__Ownable_init(admin);
__UUPSUpgradeable_init();
commitments[nextClientSequencePath] = bytes32(uint256(1));
commitments[nextChannelSequencePath] = bytes32(uint256(1));
commitments[nextConnectionSequencePath] = bytes32(uint256(1));
}
function _authorizeUpgrade(
address newImplementation
) internal override onlyOwner {}
}pragma solidity ^0.8.27;
import "../02-client/ILightClient.sol";
import "../05-port/IIBCModule.sol";
import "../Types.sol";
library IBCStoreLib {
string public constant COMMITMENT_PREFIX = "wasm";
bytes1 public constant COMMITMENT_PREFIX_PATH = 0x03;
}
abstract contract IBCStore {
// 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 clientType, address clientAddress);
event CreateClient(string clientType, uint32 clientId);
event UpdateClient(uint32 clientId, uint64 height);
event Misbehaviour(uint32 clientId);
}
/**
* @dev IBCClient is a contract that implements [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 {
if (address(clientRegistry[clientType]) != address(0)) {
revert IBCErrors.ErrClientTypeAlreadyExists();
}
clientRegistry[clientType] = address(client);
emit IBCClientLib.RegisterClient(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 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 = ILightClient(clientImpl)
.createClient(clientId, msg_.clientStateBytes, msg_.consensusStateBytes);
commitments[IBCCommitment.clientStateCommitmentKey(clientId)] =
update.clientStateCommitment;
commitments[IBCCommitment.consensusStateCommitmentKey(
clientId, update.height
)] = update.consensusStateCommitment;
emit IBCClientLib.CreateClient(msg_.clientType, clientId);
return clientId;
}
/**
* @dev updateClient updates the consensus state and the state root from a provided header
*/
function updateClient(
IBCMsgs.MsgUpdateClient calldata msg_
) external override {
ConsensusStateUpdate memory update = getClientInternal(msg_.clientId)
.updateClient(msg_.clientId, msg_.clientMessage);
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 {
getClientInternal(msg_.clientId).misbehaviour(
msg_.clientId, msg_.clientMessage
);
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 connectionId, uint32 clientId, uint32 counterpartyClientId
);
event ConnectionOpenTry(
uint32 connectionId,
uint32 clientId,
uint32 counterpartyClientId,
uint32 counterpartyConnectionId
);
event ConnectionOpenAck(
uint32 connectionId,
uint32 clientId,
uint32 counterpartyClientId,
uint32 counterpartyConnectionId
);
event ConnectionOpenConfirm(
uint32 connectionId,
uint32 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;
}
/**
* @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) {
uint32 connectionId = generateConnectionIdentifier();
IBCConnection storage connection = connections[connectionId];
connection.clientId = msg_.clientId;
connection.state = IBCConnectionState.TryOpen;
connection.counterpartyClientId = msg_.counterpartyClientId;
connection.counterpartyConnectionId = msg_.counterpartyConnectionId;
IBCConnection memory expectedConnection = IBCConnection({
state: IBCConnectionState.Init,
clientId: msg_.counterpartyClientId,
counterpartyClientId: msg_.clientId,
counterpartyConnectionId: 0
});
if (
!verifyConnectionState(
connection,
msg_.proofHeight,
msg_.proofInit,
msg_.counterpartyConnectionId,
expectedConnection
)
) {
revert IBCErrors.ErrInvalidProof();
}
commitConnection(connectionId, connection);
emit IBCConnectionLib.ConnectionOpenTry(
connectionId,
msg_.clientId,
msg_.counterpartyClientId,
msg_.counterpartyConnectionId
);
return connectionId;
}
/**
* @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 = connections[msg_.connectionId];
if (connection.state != IBCConnectionState.Init) {
revert IBCErrors.ErrInvalidConnectionState();
}
IBCConnection memory expectedConnection = IBCConnection({
state: IBCConnectionState.TryOpen,
clientId: connection.counterpartyClientId,
counterpartyClientId: connection.clientId,
counterpartyConnectionId: msg_.connectionId
});
if (
!verifyConnectionState(
connection,
msg_.proofHeight,
msg_.proofTry,
msg_.counterpartyConnectionId,
expectedConnection
)
) {
revert IBCErrors.ErrInvalidProof();
}
connection.state = IBCConnectionState.Open;
connection.counterpartyConnectionId = msg_.counterpartyConnectionId;
commitConnection(msg_.connectionId, connection);
emit IBCConnectionLib.ConnectionOpenAck(
msg_.connectionId,
connection.clientId,
connection.counterpartyClientId,
connection.counterpartyConnectionId
);
}
/**
* @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 = connections[msg_.connectionId];
if (connection.state != IBCConnectionState.TryOpen) {
revert IBCErrors.ErrInvalidConnectionState();
}
IBCConnection memory expectedConnection = IBCConnection({
state: IBCConnectionState.Open,
clientId: connection.counterpartyClientId,
counterpartyClientId: connection.clientId,
counterpartyConnectionId: msg_.connectionId
});
if (
!verifyConnectionState(
connection,
msg_.proofHeight,
msg_.proofAck,
connection.counterpartyConnectionId,
expectedConnection
)
) {
revert IBCErrors.ErrInvalidProof();
}
connection.state = IBCConnectionState.Open;
commitConnection(msg_.connectionId, connection);
emit IBCConnectionLib.ConnectionOpenConfirm(
msg_.connectionId,
connection.clientId,
connection.counterpartyClientId,
connection.counterpartyConnectionId
);
}
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(
IBCConnection storage connection,
uint64 height,
bytes calldata proof,
uint32 connectionId,
IBCConnection memory counterpartyConnection
) internal returns (bool) {
return getClientInternal(connection.clientId).verifyMembership(
connection.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;
}
}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";
import "../../lib/Hex.sol";
library IBCChannelLib {
event ChannelOpenInit(
address portId,
uint32 channelId,
bytes counterpartyPortId,
uint32 connectionId,
string version
);
event ChannelOpenTry(
address portId,
uint32 channelId,
bytes counterpartyPortId,
uint32 counterpartyChannelId,
uint32 connectionId,
string counterpartyVersion
);
event ChannelOpenAck(
address portId,
uint32 channelId,
bytes counterpartyPortId,
uint32 counterpartyChannelId,
uint32 connectionId
);
event ChannelOpenConfirm(
address portId,
uint32 channelId,
bytes counterpartyPortId,
uint32 counterpartyChannelId,
uint32 connectionId
);
event ChannelCloseInit(
address portId,
uint32 channelId,
bytes counterpartyPortId,
uint32 counterpartyChannelId
);
event ChannelCloseConfirm(
address portId,
uint32 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_.connectionId, channelId, msg_.version, msg_.relayer
);
emit IBCChannelLib.ChannelOpenInit(
msg_.portId,
channelId,
channel.counterpartyPortId,
msg_.connectionId,
msg_.version
);
return channelId;
}
/**
* @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();
}
uint32 channelId = generateChannelIdentifier();
channels[channelId] = msg_.channel;
commitChannelCalldata(channelId, msg_.channel);
claimChannel(msg_.portId, channelId);
IIBCModule(msg_.portId).onChanOpenTry(
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
);
return 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();
}
channel.state = IBCChannelState.Open;
channel.version = msg_.counterpartyVersion;
channel.counterpartyChannelId = msg_.counterpartyChannelId;
commitChannel(msg_.channelId, channel);
IIBCModule(portId).onChanOpenAck(
msg_.channelId,
msg_.counterpartyChannelId,
msg_.counterpartyVersion,
msg_.relayer
);
emit IBCChannelLib.ChannelOpenAck(
portId,
msg_.channelId,
channel.counterpartyPortId,
msg_.counterpartyChannelId,
channel.connectionId
);
}
/**
* @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();
}
channel.state = IBCChannelState.Open;
commitChannel(msg_.channelId, channel);
IIBCModule(portId).onChanOpenConfirm(msg_.channelId, msg_.relayer);
emit IBCChannelLib.ChannelOpenConfirm(
portId,
msg_.channelId,
channel.counterpartyPortId,
channel.counterpartyChannelId,
channel.connectionId
);
}
/**
* @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_.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_.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_NULL = bytes32(uint256(0));
event PacketSend(IBCPacket packet);
event PacketRecv(IBCPacket packet, address maker, bytes makerMsg);
event IntentPacketRecv(IBCPacket packet, address maker, bytes makerMsg);
event WriteAck(IBCPacket packet, bytes acknowledgement);
event PacketAck(IBCPacket packet, bytes acknowledgement, address maker);
event PacketTimeout(IBCPacket packet, address maker);
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 calldata ack
) internal pure returns (bytes32) {
return mergeAck(keccak256(abi.encodePacked(ack)));
}
function commitAckMemory(
bytes memory ack
) internal pure returns (bytes32) {
return mergeAck(keccak256(abi.encodePacked(ack)));
}
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 commitPacketMemory(
IBCPacket memory packet
) internal pure returns (bytes32) {
return keccak256(abi.encode(packet));
}
function commitPacket(
IBCPacket calldata packet
) internal pure returns (bytes32) {
return keccak256(abi.encode(packet));
}
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 {
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();
}
for (uint256 i = 0; i < l; i++) {
IBCPacket calldata packet = msg_.packets[i];
// If the channel mismatch, the commitment will be zero
bytes32 commitment = commitments[IBCCommitment
.batchPacketsCommitmentKey(
msg_.sourceChannelId, IBCPacketLib.commitPacket(packet)
)];
// Every packet must have been previously sent to be batched
if (commitment != IBCPacketLib.COMMITMENT_MAGIC) {
revert IBCErrors.ErrPacketCommitmentNotFound();
}
}
commitments[IBCCommitment.batchPacketsCommitmentKey(
msg_.sourceChannelId, IBCPacketLib.commitPackets(msg_.packets)
)] = IBCPacketLib.COMMITMENT_MAGIC;
}
function batchAcks(
IBCMsgs.MsgBatchAcks calldata msg_
) external override {
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();
}
for (uint256 i = 0; i < l; i++) {
IBCPacket calldata packet = msg_.packets[i];
bytes calldata ack = msg_.acks[i];
// If the channel mismatch, the commitment will be zero.
bytes32 commitment = commitments[IBCCommitment
.batchReceiptsCommitmentKey(
msg_.sourceChannelId, IBCPacketLib.commitPacket(packet)
)];
// 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();
}
}
commitments[IBCCommitment.batchReceiptsCommitmentKey(
msg_.sourceChannelId, IBCPacketLib.commitPackets(msg_.packets)
)] = IBCPacketLib.commitAcks(msg_.acks);
}
function sendPacket(
uint32 sourceChannel,
uint64 timeoutHeight,
uint64 timeoutTimestamp,
bytes calldata data
) external override returns (IBCPacket memory) {
if (timeoutTimestamp == 0 && timeoutHeight == 0) {
revert IBCErrors.ErrTimeoutMustBeSet();
}
if (!authenticateChannelOwner(sourceChannel)) {
revert IBCErrors.ErrUnauthorized();
}
IBCChannel storage channel = ensureChannelState(sourceChannel);
IBCPacket memory packet = IBCPacket({
sourceChannelId: sourceChannel,
destinationChannelId: channel.counterpartyChannelId,
data: data,
timeoutHeight: timeoutHeight,
timeoutTimestamp: timeoutTimestamp
});
bytes32 commitmentKey = IBCCommitment.batchPacketsCommitmentKey(
sourceChannel, IBCPacketLib.commitPacketMemory(packet)
);
if (commitments[commitmentKey] != IBCPacketLib.COMMITMENT_NULL) {
revert IBCErrors.ErrPacketAlreadyExist();
}
commitments[commitmentKey] = IBCPacketLib.COMMITMENT_MAGIC;
emit IBCPacketLib.PacketSend(packet);
return packet;
}
function setPacketReceive(
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 sourceChannelId = packets[0].sourceChannelId;
uint32 destinationChannelId = packets[0].destinationChannelId;
IBCChannel storage channel = ensureChannelState(destinationChannelId);
uint32 clientId = ensureConnectionState(channel.connectionId);
if (!intent) {
bytes32 proofCommitmentKey;
if (l == 1) {
proofCommitmentKey = IBCCommitment.batchPacketsCommitmentKey(
sourceChannelId, IBCPacketLib.commitPacket(packets[0])
);
} else {
proofCommitmentKey = IBCCommitment.batchPacketsCommitmentKey(
sourceChannelId, 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];
// Check packet height timeout
if (
packet.timeoutHeight > 0
&& (block.number >= packet.timeoutHeight)
) {
revert IBCErrors.ErrHeightTimeout();
}
// 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 (
packet.timeoutTimestamp != 0
&& (currentTimestamp >= packet.timeoutTimestamp)
) {
revert IBCErrors.ErrTimestampTimeout();
}
bytes32 commitmentKey = IBCCommitment.batchReceiptsCommitmentKey(
destinationChannelId, IBCPacketLib.commitPacket(packet)
);
if (!setPacketReceive(commitmentKey)) {
bytes memory acknowledgement;
bytes calldata makerMsg = makerMsgs[i];
if (intent) {
acknowledgement =
module.onRecvIntentPacket(packet, maker, makerMsg);
emit IBCPacketLib.IntentPacketRecv(packet, maker, makerMsg);
} else {
acknowledgement =
module.onRecvPacket(packet, maker, makerMsg);
emit IBCPacketLib.PacketRecv(packet, maker, makerMsg);
}
if (acknowledgement.length > 0) {
_writeAcknowledgement(commitmentKey, acknowledgement);
emit IBCPacketLib.WriteAck(packet, acknowledgement);
}
}
}
}
function recvPacket(
IBCMsgs.MsgPacketRecv calldata msg_
) external {
processReceive(
msg_.packets,
msg_.relayer,
msg_.relayerMsgs,
msg_.proofHeight,
msg_.proof,
false
);
}
function recvIntentPacket(
IBCMsgs.MsgIntentPacketRecv calldata msg_
) external override {
processReceive(
msg_.packets,
msg_.marketMaker,
msg_.marketMakerMsgs,
0,
msg_.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.commitAckMemory(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 commitmentKey = IBCCommitment.batchReceiptsCommitmentKey(
packet.destinationChannelId, IBCPacketLib.commitPacket(packet)
);
_writeAcknowledgement(commitmentKey, acknowledgement);
emit IBCPacketLib.WriteAck(packet, acknowledgement);
}
function acknowledgePacket(
IBCMsgs.MsgPacketAcknowledgement calldata msg_
) external override {
uint256 l = msg_.packets.length;
if (l == 0) {
revert IBCErrors.ErrNotEnoughPackets();
}
uint32 sourceChannelId = msg_.packets[0].sourceChannelId;
uint32 destinationChannelId = msg_.packets[0].destinationChannelId;
IBCChannel storage channel = ensureChannelState(sourceChannelId);
uint32 clientId = ensureConnectionState(channel.connectionId);
bytes32 commitmentKey;
bytes32 commitmentValue;
if (l == 1) {
commitmentKey = IBCCommitment.batchReceiptsCommitmentKey(
destinationChannelId, IBCPacketLib.commitPacket(msg_.packets[0])
);
commitmentValue = IBCPacketLib.commitAck(msg_.acknowledgements[0]);
} else {
commitmentKey = IBCCommitment.batchReceiptsCommitmentKey(
destinationChannelId, IBCPacketLib.commitPackets(msg_.packets)
);
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];
deletePacketCommitment(sourceChannelId, packet);
bytes calldata acknowledgement = msg_.acknowledgements[i];
module.onAcknowledgementPacket(
packet, acknowledgement, msg_.relayer
);
emit IBCPacketLib.PacketAck(packet, acknowledgement, msg_.relayer);
}
}
function timeoutPacket(
IBCMsgs.MsgPacketTimeout calldata msg_
) external override {
IBCPacket calldata packet = msg_.packet;
uint32 sourceChannelId = packet.sourceChannelId;
uint32 destinationChannelId = packet.destinationChannelId;
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 commitmentKey = IBCCommitment.batchReceiptsCommitmentKey(
destinationChannelId, IBCPacketLib.commitPacket(packet)
);
if (
!verifyAbsentCommitment(
clientId, msg_.proofHeight, msg_.proof, commitmentKey
)
) {
revert IBCErrors.ErrInvalidProof();
}
IIBCModule module = lookupModuleByChannel(sourceChannelId);
deletePacketCommitment(sourceChannelId, packet);
if (packet.timeoutTimestamp == 0 && packet.timeoutHeight == 0) {
revert IBCErrors.ErrTimeoutMustBeSet();
}
if (
packet.timeoutTimestamp > 0
&& packet.timeoutTimestamp > proofTimestamp
) {
revert IBCErrors.ErrTimeoutTimestampNotReached();
}
if (packet.timeoutHeight > 0 && packet.timeoutHeight > msg_.proofHeight)
{
revert IBCErrors.ErrTimeoutHeightNotReached();
}
module.onTimeoutPacket(packet, msg_.relayer);
emit IBCPacketLib.PacketTimeout(packet, 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 deletePacketCommitment(
uint32 sourceChannelId,
IBCPacket calldata packet
) internal {
bytes32 commitmentKey = IBCCommitment.batchPacketsCommitmentKey(
sourceChannelId, IBCPacketLib.commitPacket(packet)
);
bytes32 commitment = commitments[commitmentKey];
if (commitment != IBCPacketLib.COMMITMENT_MAGIC) {
revert IBCErrors.ErrPacketCommitmentNotFound();
}
delete commitments[commitmentKey];
}
}// 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.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/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 ERC1967) 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 ERC1167 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 ERC1822 {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 ERC1967-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 ERC1967.
*
* 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);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// 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
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}pragma solidity ^0.8.27;
import "../Types.sol";
struct ConsensusStateUpdate {
bytes32 clientStateCommitment;
bytes32 consensusStateCommitment;
uint64 height;
}
/**
* @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(
uint32 clientId,
bytes calldata clientStateBytes,
bytes calldata consensusStateBytes
) external returns (ConsensusStateUpdate memory update);
/**
* @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(
uint32 clientId,
bytes calldata clientMessageBytes
) 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(
uint32 clientId,
bytes calldata clientMessageBytes
) 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);
}pragma solidity ^0.8.27;
import "../Types.sol";
// 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 {
function onChanOpenInit(
uint32 connectionId,
uint32 channelId,
string calldata version,
address relayer
) external;
function onChanOpenTry(
uint32 connectionId,
uint32 channelId,
uint32 counterpartyChannelId,
string calldata version,
string calldata counterpartyVersion,
address relayer
) external;
function onChanOpenAck(
uint32 channelId,
uint32 counterpartyChannelId,
string calldata counterpartyVersion,
address relayer
) external;
function onChanOpenConfirm(uint32 channelId, address relayer) external;
function onChanCloseInit(uint32 channelId, address relayer) external;
function onChanCloseConfirm(uint32 channelId, address relayer) external;
function onRecvIntentPacket(
IBCPacket calldata packet,
address marketMaker,
bytes calldata marketMakerMsg
) external returns (bytes memory);
function onRecvPacket(
IBCPacket calldata packet,
address relayer,
bytes calldata relayerMsg
) external returns (bytes memory);
function onAcknowledgementPacket(
IBCPacket calldata packet,
bytes calldata acknowledgement,
address relayer
) external;
function onTimeoutPacket(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 ErrHeightTimeout();
error ErrTimestampTimeout();
error ErrAcknowledgementIsEmpty();
error ErrPacketNotReceived();
error ErrAcknowledgementAlreadyExists();
error ErrPacketCommitmentNotFound();
error ErrTimeoutHeightNotReached();
error ErrTimeoutTimestampNotReached();
error ErrNotEnoughPackets();
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 MsgConnectionOpenInit {
uint32 clientId;
uint32 counterpartyClientId;
address relayer;
}
struct MsgConnectionOpenTry {
uint32 counterpartyClientId;
uint32 counterpartyConnectionId;
uint32 clientId;
bytes proofInit;
uint64 proofHeight;
address relayer;
}
struct MsgConnectionOpenAck {
uint32 connectionId;
uint32 counterpartyConnectionId;
bytes proofTry;
uint64 proofHeight;
address relayer;
}
struct MsgConnectionOpenConfirm {
uint32 connectionId;
bytes proofAck;
uint64 proofHeight;
address relayer;
}
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;
bytes emptyProof;
}
struct MsgBatchSend {
uint32 sourceChannelId;
IBCPacket[] packets;
}
struct MsgBatchAcks {
uint32 sourceChannelId;
IBCPacket[] packets;
bytes[] acks;
}
struct MsgMisbehaviour {
uint32 clientId;
bytes clientMessage;
}
}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(
uint32 channelId,
bytes32 batchHash
) internal pure returns (bytes memory) {
return abi.encode(PACKETS, channelId, batchHash);
}
function batchReceiptsCommitmentPath(
uint32 channelId,
bytes32 batchHash
) internal pure returns (bytes memory) {
return abi.encode(PACKET_ACKS, channelId, 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(
uint32 channelId,
bytes32 batchHash
) internal pure returns (bytes32) {
return keccak256(batchPacketsCommitmentPath(channelId, batchHash));
}
function batchReceiptsCommitmentKey(
uint32 channelId,
bytes32 batchHash
) internal pure returns (bytes32) {
return keccak256(batchReceiptsCommitmentPath(channelId, 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 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;
/// @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 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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 `length` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2 + 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexString(uint256 value, uint256 length)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value, length);
/// @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 `length` bytes.
/// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexStringNoPrefix(uint256 value, uint256 length)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `length * 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, length), 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(length, length))
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 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.
let end := add(i, mload(subject))
if iszero(gt(needleLen, mload(subject))) {
let subjectSearchEnd := add(sub(end, 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 n := add(sub(d, add(result, 0x20)), end)
// Copy the rest of the string 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 string.
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(string memory subject, string 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(string memory subject, string memory needle)
internal
pure
returns (uint256 result)
{
result = 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(string memory subject, string 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(string memory subject, string memory needle)
internal
pure
returns (uint256 result)
{
result = lastIndexOf(subject, 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 indexOf(subject, needle) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(string memory subject, string memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let needleLen := mload(needle)
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
iszero(gt(needleLen, mload(subject))),
eq(
keccak256(add(subject, 0x20), needleLen),
keccak256(add(needle, 0x20), needleLen)
)
)
}
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(string memory subject, string memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let needleLen := mload(needle)
// Whether `needle` is not longer than `subject`.
let inRange := iszero(gt(needleLen, mload(subject)))
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
eq(
keccak256(
// `subject + 0x20 + max(subjectLen - needleLen, 0)`.
add(add(subject, 0x20), mul(inRange, sub(mload(subject), needleLen))),
needleLen
),
keccak256(add(needle, 0x20), needleLen)
),
inRange
)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(string memory subject, uint256 times)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLen := mload(subject)
if iszero(or(iszero(times), iszero(subjectLen))) {
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, subjectLen)) { break }
}
o := add(o, subjectLen)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(o, 0) // Zeroize the slot after the string.
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(string memory subject, uint256 start, uint256 end)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLen := mload(subject)
if iszero(gt(subjectLen, end)) { end := subjectLen }
if iszero(gt(subjectLen, start)) { start := subjectLen }
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 string.
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 string.
/// `start` is a byte offset.
function slice(string memory subject, uint256 start)
internal
pure
returns (string memory result)
{
result = slice(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 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 strings based on the `delimiter` inside of the `subject` string.
function split(string memory subject, string memory delimiter)
internal
pure
returns (string[] 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 string.
// 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 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 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 string.
mstore(result, totalLen) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate memory.
}
}
/// @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 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 {
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;
library Hex {
error ErrInvalidHexAddress();
// Convert 32 hexadecimal digits into 16 bytes.
function hexToBytes16(
bytes32 h
) internal pure returns (bytes16 b) {
unchecked {
// Ensure all chars below 128
if (
h
&
0x8080808080808080808080808080808080808080808080808080808080808080
!= 0
) {
revert ErrInvalidHexAddress();
}
// Subtract '0' from every char
h = bytes32(
uint256(h)
-
0x3030303030303030303030303030303030303030303030303030303030303030
);
// Ensure all chars still below 128, i.e. no underflow in the previous line
if (
h
&
0x8080808080808080808080808080808080808080808080808080808080808080
!= 0
) {
revert ErrInvalidHexAddress();
}
// Calculate mask for chars that originally were above '9'
bytes32 ndm = bytes32(
(
(
(
uint256(h)
+
0x7676767676767676767676767676767676767676767676767676767676767676
)
&
0x8080808080808080808080808080808080808080808080808080808080808080
) >> 7
) * 0xFF
);
// Subtract 7 ('A' - '0') from every char that originally was above '9'
h = bytes32(
uint256(h)
- uint256(
ndm
&
0x0707070707070707070707070707070707070707070707070707070707070707
)
);
// Ensure all chars still below 128, i.e. no underflow in the previous line
if (
h
&
0x8080808080808080808080808080808080808080808080808080808080808080
!= 0
) {
revert ErrInvalidHexAddress();
}
// Ensure chars that originally were above '9' are now above 9
if (
(
uint256(h)
- uint256(
ndm
&
0x0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A
)
)
&
0x8080808080808080808080808080808080808080808080808080808080808080
!= 0
) {
revert ErrInvalidHexAddress();
}
// Calculate Mask for chars that originally were above 'F'
bytes32 lcm = bytes32(
(
(
(
uint256(h)
+
0x7070707070707070707070707070707070707070707070707070707070707070
)
&
0x8080808080808080808080808080808080808080808080808080808080808080
) >> 7
) * 0xFF
);
// Subtract 32 ('a' - 'A') from all chars that oroginally were above 'F'
h = bytes32(
uint256(h)
- uint256(
lcm
&
0x2020202020202020202020202020202020202020202020202020202020202020
)
);
// Ensure chars that originally were above 'F' are now above 9
if (
(
uint256(h)
- uint256(
lcm
&
0x0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A
)
)
&
0x8080808080808080808080808080808080808080808080808080808080808080
!= 0
) {
revert ErrInvalidHexAddress();
}
// Ensure all chars are below 16
if (
h
&
0xF0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0
!= 0
) {
revert ErrInvalidHexAddress();
}
// 0x0A0B0C0D... -> 0xAB00CD00...
h = (
(
h
&
0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00
) << 4
)
| (
(
h
&
0x000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F
) << 8
);
// 0xAA00BB00CC00DD00... -> 0xAABB0000CCDD0000...
h = (
h
&
0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
)
| (
(
h
&
0x0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF00
) << 8
);
// 0xAAAA0000BBBB0000CCCC0000DDDD0000... -> 0xAAAABBBB00000000CCCCDDDD00000000...
h = (
h
&
0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000
)
| (
(
h
&
0x00000000FFFF000000000000FFFF000000000000FFFF000000000000FFFF0000
) << 16
);
// 0xAAAAAAAA00000000BBBBBBBB00000000CCCCCCCC00000000DDDDDDDD00000000 -> 0xAAAAAAAABBBBBBBB0000000000000000CCCCCCCCDDDDDDDD0000000000000000
h = (
h
&
0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000
)
| (
(
h
&
0x0000000000000000FFFFFFFF000000000000000000000000FFFFFFFF00000000
) << 32
);
// 0xAAAAAAAAAAAAAAAA0000000000000000BBBBBBBBBBBBBBBB0000000000000000 -> 0xAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB00000000000000000000000000000000
h = (
h
&
0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000
)
| (
(
h
&
0x00000000000000000000000000000000FFFFFFFFFFFFFFFF0000000000000000
) << 64
);
// Trim to 16 bytes
b = bytes16(h);
}
}
function hexToAddress(
string memory s
) internal pure returns (address) {
if (bytes(s).length != 42) {
revert ErrInvalidHexAddress();
}
bytes2 prefix;
bytes32 leftHex;
bytes32 rightHex;
assembly {
prefix := mload(add(s, 0x20))
leftHex := mload(add(s, 0x22))
rightHex := mload(add(s, 0x2A))
}
if (prefix != "0x") {
revert ErrInvalidHexAddress();
}
bytes16 left = hexToBytes16(leftHex);
bytes16 right = hexToBytes16(rightHex);
return address(bytes20(left) | (bytes20(right) >> 32));
}
function atoi(
bytes1 b
) internal pure returns (uint8 res) {
if (b >= "0" && b <= "9") {
return uint8(b) - uint8(bytes1("0"));
} else if (b >= "A" && b <= "F") {
return 10 + uint8(b) - uint8(bytes1("A"));
} else if (b >= "a" && b <= "f") {
return 10 + uint8(b) - uint8(bytes1("a"));
}
return uint8(b);
}
function hexToUint256(
string memory s
) internal pure returns (uint256) {
bytes memory b = bytes(s);
uint256 number;
for (uint256 i = 2; i < b.length; i++) {
number = number << 4;
number |= atoi(b[i]);
}
return number;
}
}pragma solidity ^0.8.27;
import "../25-handler/IBCMsgs.sol";
interface IIBCPacket {
/**
* @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);
/**
* @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;
/**
* @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 fullfilling the intent executes the expected effects.
*/
function recvIntentPacket(
IBCMsgs.MsgIntentPacketRecv calldata msg_
) external;
/**
* @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;
/**
* @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;
/**
* @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;
/**
* @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;
/**
* @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;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: 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.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @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);
/**
* @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 EIP1967 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 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 EIP1967) 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 EIP1967 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 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 EIP1967 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 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.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) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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 ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* 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;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}{
"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/"
],
"optimizer": {
"enabled": true,
"runs": 1000,
"details": {
"cse": true,
"constantOptimizer": true,
"yul": true
}
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {}
}Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"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":"ErrClientNotFound","type":"error"},{"inputs":[],"name":"ErrClientTypeAlreadyExists","type":"error"},{"inputs":[],"name":"ErrClientTypeNotFound","type":"error"},{"inputs":[],"name":"ErrCommittedAckNotPresent","type":"error"},{"inputs":[],"name":"ErrHeightTimeout","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":"ErrPacketAlreadyExist","type":"error"},{"inputs":[],"name":"ErrPacketCommitmentNotFound","type":"error"},{"inputs":[],"name":"ErrPacketNotReceived","type":"error"},{"inputs":[],"name":"ErrTimeoutHeightNotReached","type":"error"},{"inputs":[],"name":"ErrTimeoutMustBeSet","type":"error"},{"inputs":[],"name":"ErrTimeoutTimestampNotReached","type":"error"},{"inputs":[],"name":"ErrTimestampTimeout","type":"error"},{"inputs":[],"name":"ErrUnauthorized","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"portId","type":"address"},{"indexed":false,"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":false,"internalType":"address","name":"portId","type":"address"},{"indexed":false,"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":false,"internalType":"address","name":"portId","type":"address"},{"indexed":false,"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":false,"internalType":"address","name":"portId","type":"address"},{"indexed":false,"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":false,"internalType":"address","name":"portId","type":"address"},{"indexed":false,"internalType":"uint32","name":"channelId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"counterpartyPortId","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":false,"internalType":"string","name":"version","type":"string"}],"name":"ChannelOpenInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"portId","type":"address"},{"indexed":false,"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":false,"internalType":"string","name":"counterpartyVersion","type":"string"}],"name":"ChannelOpenTry","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":false,"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":false,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":false,"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":false,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"counterpartyClientId","type":"uint32"}],"name":"ConnectionOpenInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"connectionId","type":"uint32"},{"indexed":false,"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":false,"internalType":"string","name":"clientType","type":"string"},{"indexed":false,"internalType":"uint32","name":"clientId","type":"uint32"}],"name":"CreateClient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"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"}],"indexed":false,"internalType":"struct IBCPacket","name":"packet","type":"tuple"},{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"bytes","name":"makerMsg","type":"bytes"}],"name":"IntentPacketRecv","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"clientId","type":"uint32"}],"name":"Misbehaviour","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"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"},{"indexed":false,"internalType":"bytes","name":"acknowledgement","type":"bytes"},{"indexed":false,"internalType":"address","name":"maker","type":"address"}],"name":"PacketAck","type":"event"},{"anonymous":false,"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"}],"indexed":false,"internalType":"struct IBCPacket","name":"packet","type":"tuple"},{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"bytes","name":"makerMsg","type":"bytes"}],"name":"PacketRecv","type":"event"},{"anonymous":false,"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"}],"indexed":false,"internalType":"struct IBCPacket","name":"packet","type":"tuple"}],"name":"PacketSend","type":"event"},{"anonymous":false,"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"}],"indexed":false,"internalType":"struct IBCPacket","name":"packet","type":"tuple"},{"indexed":false,"internalType":"address","name":"maker","type":"address"}],"name":"PacketTimeout","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"clientType","type":"string"},{"indexed":false,"internalType":"address","name":"clientAddress","type":"address"}],"name":"RegisterClient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"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":[{"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"},{"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":[{"components":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"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":[{"internalType":"uint32","name":"sourceChannelId","type":"uint32"},{"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":"address","name":"relayer","type":"address"}],"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":"address","name":"relayer","type":"address"}],"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":"address","name":"relayer","type":"address"}],"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":"address","name":"relayer","type":"address"}],"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":[{"internalType":"uint32","name":"clientId","type":"uint32"}],"name":"getClient","outputs":[{"internalType":"contract ILightClient","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bytes","name":"clientMessage","type":"bytes"}],"internalType":"struct IBCMsgs.MsgMisbehaviour","name":"msg_","type":"tuple"}],"name":"misbehaviour","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"bytes","name":"emptyProof","type":"bytes"}],"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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"sourceChannel","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":[{"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":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","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
60a06040523461003c5730608052610015610041565b61001d610041565b6040516151e2908161010082396080518181816128dd01526129940152f35b600080fd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c166100ee576002600160401b03196001600160401b038216016100895750565b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b63f92ee8a960e01b60005260046000fdfe6080604052600436101561001257600080fd5b60003560e01c80630e04968414613b3e578063113a1b7014613a8d5780631296c14814613a3857806318c19870146139335780632b2c5463146132c15780634127910814612f70578063441fd11514612bf95780634f1ef2861461295757806352d1902d146128c25780635a06a1881461273d5780635f5d288e146126fd5780636415d1a3146123ab57806370a31901146122ce578063715018a61461223557806382a09c151461204a578063839df9451461201e57806383c808ff14611f2f5780638548fbbe14611e665780638da5cb5b14611e20578063990491a514611daa578063999d5c6b14611b585780639aa0346f1461172d5780639f18077b1461163a578063ad3cb1cc146115db578063afc3619b146112d3578063b1892e401461126d578063b69562bd146110c3578063baec252714610f04578063c4d66de814610beb578063c8982e1514610a6b578063db305c1c1461097b578063de844ebc1461093b578063dea5a7231461090c578063dee97dc614610796578063e5cbff7914610567578063f2fde38b1461053c5763fed12cbf146101b357600080fd5b34610537576101c1366140f9565b6001600160a01b0360206101d583806142f0565b9190826040519384928337810160018152030190205416801561050d577f9b9820486a05c0193efb214c6c2ba8fce02c5a5c84aa057f8199c99f13ff939b600052600060205263ffffffff604060002054169063ffffffff610236836148de565b7f9b9820486a05c0193efb214c6c2ba8fce02c5a5c84aa057f8199c99f13ff939b6000908152602052167fa17c46f2d2a87aa05f956999001178d4f3a177d856047a83ccebd64d7a2ef49d5561028c83806142f0565b8360005260026020526040600020916001600160401b0382116104f7576102bd826102b78554613f30565b8561438f565b600090601f831160011461048957926102f98361038794610399979460609760009261047e575b50508160011b916000199060031b1c19161790565b90555b84600052600360205260406000206001600160a01b0382166001600160a01b0319825416179055600061033260208801886142f0565b61034260408a949394018a6142f0565b9790604051988997889687957fae3fee350000000000000000000000000000000000000000000000000000000087528d60048801528b60248801526064870191614322565b84810360031901604486015291614322565b03925af1908115610472576020937f6e071f9d82ad3d0aaae325775210a4689898ec9475243a1a0692d374a6ad1f469261041c92600091610443575b5080516103e186614f9e565b600052600087526040600020556104096001600160401b036040888401519301511686614fc4565b60005260008652604060002055806142f0565b610433604051928392604084526040840191614322565b84868301520390a1604051908152f35b610465915060603d60601161046b575b61045d8183614023565b810190614618565b386103d5565b503d610453565b6040513d6000823e3d90fd5b0135905038806102e4565b8382526020822091601f198416815b8181106104df5750936103999693606096936001938361038798106104c5575b505050811b0190556102fc565b0135600019600384901b60f8161c191690553880806104b8565b91936020600181928787013581550195019201610498565b634e487b7160e01b600052604160045260246000fd5b7faa478af90000000000000000000000000000000000000000000000000000000060005260046000fd5b600080fd5b346105375760203660031901126105375761056561055861412c565b610560614bfa565b614662565b005b3461053757608036600319011261053757610580613f0c565b6024356001600160401b03811680910361053757604435916001600160401b038316809303610537576064356001600160401b038111610537576105c8903690600401614099565b939092600060806040516105db81613fed565b82815282602082015260606040820152826060820152015281158061078e575b610764576106258363ffffffff1660005260066020526001600160a01b0360406000205416331490565b1561073a576106676106a39463ffffffff61063f86614d35565b5460281c16966040519761065289613fed565b63ffffffff871689526020890152369161415d565b604086015260608501526080840152604051602081019061069a8161068c8785614239565b03601f198101835282614023565b51902090614c7e565b908160005260006020526040600020546107105761070c916000526000602052600160f81b6040600020557ff58a2d54b6bf8f57965fae5cadacc16f93672604359e3623141d22248ac71a75604051806106fd8482614239565b0390a160405191829182614239565b0390f35b7fa29bd6ea0000000000000000000000000000000000000000000000000000000060005260046000fd5b7fcc12cef60000000000000000000000000000000000000000000000000000000060005260046000fd5b7fddd92f790000000000000000000000000000000000000000000000000000000060005260046000fd5b5080156105fb565b34610537576108146107a7366141f2565b606060006001600160a01b036107c46107bf8561437e565b614baa565b166107ce8461437e565b6107db60208601866142f0565b939091604051978895869485937ff67f54fa0000000000000000000000000000000000000000000000000000000085526004850161445f565b03925af1908115610472577f078276040a4f9f4dea1214e38413d6bac929b39330be19599176564d23d5ef41926000926108de575b506108aa6001600160401b039183516108696108648361437e565b614f9e565b60005260006020526040600020556020840151610897604061088a8461437e565b9601958587511690614fc4565b600052600060205260406000205561437e565b915116906108d9604051928392839092916001600160401b0360209163ffffffff604085019616845216910152565b0390a1005b6001600160401b039192506109046108aa9160603d60601161046b5761045d8183614023565b929150610849565b3461053757602036600319011261053757602061092a6107bf613f0c565b6001600160a01b0360405191168152f35b346105375760203660031901126105375763ffffffff610959613f0c565b16600052600660205260206001600160a01b0360406000205416604051908152f35b346105375760603660031901126105375760206000610a1761099b614a18565b9163ffffffff8316928382526004855260408220916109d76109bb614358565b845464ffffffff00191660089190911b64ffffffff0016178455565b50815460ff19166001178255610a126109ee61436b565b835468ffffffff0000000000191660289190911b68ffffffff000000000016178355565b614b53565b7f5c19396f17b2d5b8ebfa9d37569101115f64e85557fe202593aa3e5555bad05d6060610a42614358565b63ffffffff610a4f61436b565b81604051938785521687840152166040820152a1604051908152f35b3461053757610a79366141f2565b60208101610a878183614293565b92905060028310610bc157604081019260005b818110610aee5783610adb84610ad5610acf610abf610ab98b85614293565b90614ed9565b94610ac98461437e565b93614293565b90614cab565b90614d60565b6000526000602052604060002055600080f35b610b2e610b0582610aff8787614293565b906144b0565b610b1983610b138988614293565b906145ca565b929091610ad5610b288861437e565b91614c5b565b60005260006020526040600020549182158015610bb4575b610b8a57610b5391614f6d565b03610b6057600101610a9a565b7f59c3580a0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f2430f4030000000000000000000000000000000000000000000000000000000060005260046000fd5b50600160f81b8314610b46565b7f5458d3430000000000000000000000000000000000000000000000000000000060005260046000fd5b3461053757602036600319011261053757610c0461412c565b60008051602061518d833981519152549060ff8260401c1615916001600160401b03811680159081610efc575b6001149081610ef2575b159081610ee9575b50610e775767ffffffffffffffff19811660011760008051602061518d8339815191525582610ebc575b5060008051602061518d8339815191525460ff8160401c1615916001600160401b03821680159081610eb4575b6001149081610eaa575b159081610ea1575b50610e775767ffffffffffffffff19821660011760008051602061518d83398151915255610ceb9183610e4a575b50610ce36150b5565b6105606150b5565b610cf36150b5565b6000602081905260017fa17c46f2d2a87aa05f956999001178d4f3a177d856047a83ccebd64d7a2ef49d8190557fa948e29ac0e6a6a5e3c647a07a0505170c972dd4960cbe194aee77626bb52b588190557f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a9091527f24072874bb11662934f0c68ca2659a14efae71555bb48eba2450fe6433183f9555610dee575b610d9557005b68ff00000000000000001960008051602061518d833981519152541660008051602061518d833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b68ff00000000000000001960008051602061518d833981519152541660008051602061518d833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1610d8f565b68ffffffffffffffffff1916680100000000000000011760008051602061518d8339815191525584610cda565b7ff92ee8a90000000000000000000000000000000000000000000000000000000060005260046000fd5b90501585610cac565b303b159150610ca4565b849150610c9a565b68ffffffffffffffffff1916680100000000000000011760008051602061518d8339815191525582610c6d565b90501584610c43565b303b159150610c3b565b849150610c31565b3461053757610f1236613ed9565b63ffffffff610f208261437e565b1660005260046020526040600020805460ff811660048110156110ad576001036110835763ffffffff610f528461437e565b8160405193610f6085614008565b60028552818160281c16602086015260081c166040840152166060820152610fb1610f8d606085016142dc565b91610f9b60408601866142f0565b602087019491610faa8661437e565b9287614aaa565b15611072577fdb439789af7a0ed4968cc1f35b0c7dfd9c878c6508bd7fd48053e87df31231d09261101e610ff261103093600360ff1987541617865561437e565b84546cffffffff000000000000000000191660489190911b6cffffffff00000000000000000016178455565b61102b83610a128361437e565b61437e565b90546040805163ffffffff9384168152600883901c84166020820152602883901c84169181019190915260489190911c909116606082015280608081016108d9565b630a104c9960e11b60005260046000fd5b7f8ca989900000000000000000000000000000000000000000000000000000000060005260046000fd5b634e487b7160e01b600052602160045260246000fd5b3461053757604036600319011261053757600063ffffffff6110e3614358565b168152600560205260408120805460ff811660058110156112595760030361124a5763ffffffff6111179160081c166147b3565b50805460ff191660041781556111348161112f614358565b614988565b63ffffffff611141614358565b1682526006602052816001600160a01b0360408220541691611161614358565b92602435936001600160a01b038516850361124657813b15611246576040517fc2c0030b00000000000000000000000000000000000000000000000000000000815263ffffffff9190911660048201526001600160a01b03949094166024850152828460448183855af190811561123b577f5d4b57424fd8ef7d85bed4d570d10b0bf5d38ef1936569ba4ca1f62ff78836e5946001946112259361122b575b505061120a614358565b9063ffffffff845460281c169160405195869501918561447c565b0390a180f35b61123491614023565b8686611200565b6040513d85823e3d90fd5b8380fd5b600483634b6848a360e11b8152fd5b602484634e487b7160e01b81526021600452fd5b346105375760203660031901126105375763ffffffff61128b613f0c565b166000526004602052608060406000205463ffffffff604051916112b28360ff83166141e5565b818160081c166020840152818160281c16604084015260481c166060820152f35b34610537576112e136613ed9565b6112eb8180614293565b8092915015610bc1576112fe8180614293565b156115995761102b8161131092614343565b9161131b8280614293565b1561159957602061132f8261133593614343565b0161437e565b61135063ffffffff61134686614d35565b5460081c166147b3565b90600183036115af576113638480614293565b9190911561159957610ad561137b8361138094614343565b614c5b565b9061138e6020850185614293565b9190911561159957611445926113af6113a9846020956142f0565b90614f6d565b915b60006113bf606089016142dc565b916113cd60408a018a6142f0565b9790956001600160a01b036113e184614baa565b169560405190898201528881526113f9604082614023565b604051918983015288825261140f604083614023565b604051998a98899788967fa9f9396e000000000000000000000000000000000000000000000000000000008852600488016147ff565b03925af19081156104725760009161156a575b5015611072579061146883614d8d565b906001600160a01b0360009216906020810160808201935b85811061148957005b61149781610aff8580614293565b906114a28289614ddd565b6114b081610b138587614293565b92906114bb886142c8565b91873b156105375760006114ff93604051809581927ff33d7175000000000000000000000000000000000000000000000000000000008352898787600486016145e5565b0381838c5af18015610472576001957f58ecb5cdbc94a25c1a782bb33f66684c1804b56e0d8b3a666160f6e5896f311e9461155092611559575b506115438b6142c8565b90604051948594856145e5565b0390a101611480565b600061156491614023565b8d611539565b61158c915060203d602011611592575b6115848183614023565b8101906147e7565b84611458565b503d61157a565b634e487b7160e01b600052603260045260246000fd5b611445916115c6602092610ad5610acf8880614293565b6115d5610ab984880188614293565b916113b1565b346105375760003660031901126105375761070c60408051906115fe8183614023565b600582527f352e302e30000000000000000000000000000000000000000000000000000000602083015251918291602083526020830190614074565b34610537576040366003190112610537576004356001600160401b03811161053757806004019060a06003198236030112610537576024356001600160401b0381116105375761168e903690600401614194565b90815115610b8a57602401916116c86116a68461437e565b63ffffffff1660005260066020526001600160a01b0360406000205416331490565b1561073a5761171e826117196117108661170a6117057fdc54d6fa75b81ef04ee8e27b86d4deabbc0dbc79d0b30f70349d335fc29cf7649961437e565b614d35565b5061437e565b610ad585614c5b565b614e13565b6108d9604051928392836145a5565b346105375761173b366140f9565b6117458180614343565b61174e8161437e565b61175a6020830161437e565b61176b63ffffffff61134684614d35565b906001600160a01b0361177d83614baa565b16916117e360206040880194611792866142dc565b6040517fe9946fc300000000000000000000000000000000000000000000000000000000815263ffffffff861660048201526001600160401b03909116602482015292839190829081906044820190565b03915afa801561047257600090611b18575b6001600160401b03915016918215611aee57866118b863ffffffff60006001600160401b03956118ca61182d602097610ad58e614c5b565b6118436118398c6142dc565b97898101906142f0565b96906001600160a01b0361185686614baa565b1697604051938b8501528a845261186e604085614023565b6040519b8c9a8b998a987f3fd413de000000000000000000000000000000000000000000000000000000008a52166004890152166024870152608060448701526084860191614322565b83810360031901606485015290614074565b03925af190811561047257600091611acf575b5015611072576118f6846118f085614d8d565b94614ddd565b60808401906001600160401b0361190c836142dc565b161580611ab3575b610764576001600160401b03611929836142dc565b1615159182611a96575b5050611a6c5760608301906001600160401b0361194f836142dc565b1615159182611a43575b5050611a19576001600160a01b031691606001611975816142c8565b92803b15610537576119bc6000949185926040519687809481937fda6a79860000000000000000000000000000000000000000000000000000000083528960048401614585565b03925af1908115610472577f4493027da4552008217d5c8f83ace2a1a78d2ae45b427b49c0c363be9a2d7aea936119f892611a08575b506142c8565b906108d960405192839283614585565b6000611a1391614023565b846119f2565b7f12c51c640000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160401b03919250611a61611a5b83926142dc565b936142dc565b169116118480611959565b7f8551d2350000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160401b03919250611aaa906142dc565b16118580611933565b506001600160401b03611ac8606087016142dc565b1615611914565b611ae8915060203d602011611592576115848183614023565b866118dd565b7f9b6c9adc0000000000000000000000000000000000000000000000000000000060005260046000fd5b506020813d602011611b50575b81611b3260209383614023565b8101031261053757611b4b6001600160401b03916144c7565b6117f5565b3d9150611b25565b3461053757611b66366140f9565b63ffffffff611b748261437e565b166000526005602052604060002080549060ff821660058110156110ad57600203611d9957611ca063ffffffff8360081c16611baf816147b3565b63ffffffff611bbd8761437e565b16600052600660205263ffffffff604060002054956001600160a01b0387169682611c0b611bea8b61437e565b9663ffffffff16600052600460205263ffffffff60406000205460481c1690565b95604051926bffffffffffffffffffffffff199060601b16602084015260148352611c37603484614023565b8160405197611c4589613fed565b600389521660208801521660408601526060850152604051611c7581611c6e8160028b01613f6a565b0382614023565b6080850152611c86604089016142dc565b611c9360208a018a6142f0565b93909260281c1693614852565b1561107257805460ff19166003178155611cbd8161112f8561437e565b611cc68361437e565b611cd2606085016142c8565b90833b15610537576040517f423b7df600000000000000000000000000000000000000000000000000000000815263ffffffff9190911660048201526001600160a01b0391909116602482015260008160448183875af18015610472577f03c5f9b30a58d1ae49f1cff4d32c3906e7705104c0e815b97492af31137cb9fb946108d992611d6392611d88575061437e565b91805490604051948594600163ffffffff808660081c169560281c169301918661441d565b6000611d9391614023565b8661170a565b634b6848a360e11b60005260046000fd5b34610537576020366003190112610537576004356001600160401b0381116105375736602382011215610537576001600160a01b03611e0c6020611df98194369060248160040135910161415d565b8160405193828580945193849201614051565b810160018152030190205416604051908152f35b346105375760003660031901126105375760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b3461053757611e74366141b2565b60208101611e828183614293565b905060028110610bc15760005b818110611ec857611eb084611eaa610acf86610ac98461437e565b90614c7e565b6000526000602052600160f81b604060002055600080f35b611ee5611ed982610aff8688614293565b611eaa610b288761437e565b6000526000602052600160f81b60406000205403611f0557600101611e8f565b7f4d7cfc570000000000000000000000000000000000000000000000000000000060005260046000fd5b3461053757611f3d366140f9565b63ffffffff611f4b8261437e565b1660005260046020526040600020805460ff811660048110156110ad5760020361108357611fdc90611f7c8461437e565b9063ffffffff60405192611f8f84614008565b60038452818360281c166020850152818360081c16604085015216606083015263ffffffff611fc0604087016142dc565b91611fce60208801886142f0565b92909160481c169286614aaa565b15611072576110307fc382cf337d6f6a49bfb3fb8ec3fa62783704bd87aa72d534ff1b99195050aad892600360ff1984541617835561102b83610a128361437e565b346105375760203660031901126105375760043560005260006020526020604060002054604051908152f35b3461053757612058366140f9565b63ffffffff6120668261437e565b16600052600560205260406000209081549160ff831660058110156110ad57600303611d995761215e63ffffffff8460081c166120a2816147b3565b63ffffffff6120b08661437e565b16600052600660205263ffffffff604060002054966001600160a01b03881697826120dd611bea8a61437e565b95604051926bffffffffffffffffffffffff199060601b16602084015260148352612109603484614023565b816040519761211789613fed565b60048952166020880152166040860152606085015260405161214081611c6e8160028b01613f6a565b6080850152612151604088016142dc565b611c9360208901896142f0565b1561107257805460ff1916600417815561217b8161112f8461437e565b6121848261437e565b612190606084016142c8565b90843b15610537576040517f578392c500000000000000000000000000000000000000000000000000000000815263ffffffff9190911660048201526001600160a01b0391909116602482015260008160448183885af19384156104725761120a6001946108d9937ff55ea0b61aba75ba1463c3325f7b0a06baa2d96ee4a621a05dabdf03b489c41d97612224575061437e565b600061222f91614023565b8761170a565b346105375760003660031901126105375761224e614bfa565b60006001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610537576122dc366141b2565b6001600160a01b036122f06107bf8361437e565b166122fa8261437e565b61230760208401846142f0565b9092803b156105375761234e9360008094604051968795869485937fa4479b110000000000000000000000000000000000000000000000000000000085526004850161445f565b03925af18015610472577f2d86933ea68552f2484167a027c9e1a658fee909dffcc151fb2d4fde750311269260209261238b9261239a575061437e565b63ffffffff60405191168152a1005b60006123a591614023565b8461170a565b34610537576123b9366140c6565b63ffffffff6123c78261437e565b1660005260056020526040600020805460ff811660058110156110ad57600103611d995760081c63ffffffff16906123fe826147b3565b9263ffffffff61240d8261437e565b166000526006602052604060002054936124fc6001600160a01b038616946124c861245b61243a8661437e565b9263ffffffff16600052600460205263ffffffff60406000205460481c1690565b91604051986bffffffffffffffffffffffff199060601b1660208a01526014895261248760348a614023565b63ffffffff602087019961249b8b896142f0565b92909381604051976124ac89613fed565b600289521660208801521660408601526060850152369161415d565b60808201526124d9608085016142dc565b926124e760608601866142f0565b9060408701956124f68761437e565b93614852565b1561107257825460ff1916600317835561251685836142f0565b60028501916001600160401b0382116104f757612537826102b78554613f30565b600090601f83116001146126995761256792916000918361268e5750508160011b916000199060031b1c19161790565b90555b61259a6125768261437e565b845468ffffffff0000000000191660289190911b68ffffffff000000000016178455565b6125a78361112f8461437e565b6125b08261437e565b946125c46125bd8361437e565b91846142f0565b9190966125d360a086016142c8565b92873b1561053757600093612616916040519a8b9586957f5209209d000000000000000000000000000000000000000000000000000000008752600487016143e1565b038183885af19384156104725761266261265c6108d9947f958d927ded58a29a450e24013886756bcee58e1146c05e9d0c671e5003cf8d909860019861267d575061437e565b9261437e565b9063ffffffff855460081c169260405196879601918661441d565b600061268891614023565b8961170a565b0135905089806102e4565b8382526020822091601f198416815b8181106126e557509084600195949392106126cb575b505050811b01905561256a565b0135600019600384901b60f8161c191690558880806126be565b919360206001819287870135815501950192016126a8565b346105375760203660031901126105375763ffffffff61271b613f0c565b16600052600360205260206001600160a01b0360406000205416604051908152f35b346105375761274b366140c6565b612753614a18565b9063ffffffff821690816000526004602052604060002090604081019361277c6109bb8661437e565b825460ff191660021783556127936125768361437e565b60208201946127d06127a48761437e565b85546cffffffff000000000000000000191660489190911b6cffffffff00000000000000000016178555565b6128396127dc8461437e565b63ffffffff6127ea8461437e565b81604051936127f885614008565b600185521660208401521660408201526000606082015261281b608086016142dc565b61282860608701876142f0565b906128328b61437e565b9289614aaa565b156110725760209561288561287f6128796128b79461102b7f0a9d00e740d5a7292ecf25db89826a19ca7963a06c398a7f95947e84d1ce8f319988614b53565b9561437e565b9161437e565b9060405194859485929363ffffffff809296958160609581608089019a16885216602087015216604085015216910152565b0390a1604051908152f35b34610537576000366003190112610537576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361292d5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b7fe07c8dba0000000000000000000000000000000000000000000000000000000060005260046000fd5b60403660031901126105375761296b61412c565b6024356001600160401b0381116105375761298a903690600401614194565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803014908115612bc4575b5061292d576129cc614bfa565b6001600160a01b038216916040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481875afa60009181612b90575b50612a295783634c9c8ce360e01b60005260045260246000fd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc859203612b635750813b15612b4f57806001600160a01b03197f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2815115612b1c5760008083602061056595519101845af43d15612b14573d91612af783614142565b92612b056040519485614023565b83523d6000602085013e6150fc565b6060916150fc565b505034612b2557005b7fb398979f0000000000000000000000000000000000000000000000000000000060005260046000fd5b634c9c8ce360e01b60005260045260246000fd5b7faa1d49a40000000000000000000000000000000000000000000000000000000060005260045260246000fd5b9091506020813d602011612bbc575b81612bac60209383614023565b8101031261053757519085612a0f565b3d9150612b9f565b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54161415836129bf565b3461053757612c0736613ed9565b60408101612c1c612c178261437e565b6147b3565b50612c256148f6565b9063ffffffff821691826000526005602052604060002091600160ff19845416178355612c546109bb8261437e565b6060850194612c6386826142f0565b60028601916001600160401b0382116104f757612c84826102b78554613f30565b600090601f8311600114612f0c57612cb4929160009183612f015750508160011b916000199060031b1c19161790565b90555b612cc460208201826142f0565b6001860195916001600160401b0382116104f757612cec82612ce68954613f30565b8961438f565b600090601f8311600114612e99579180612d2192612d2a9594600092612e8e5750508160011b916000199060031b1c19161790565b86555b84614988565b612d6683612d37836142c8565b9063ffffffff1660005260066020526001600160a01b03604060002091166001600160a01b0319825416179055565b6001600160a01b03612d77826142c8565b1692612d828361437e565b90612d8d88846142f0565b959091612d9c608086016142c8565b823b1561053757600094612de186926040519a8b97889687957f27e756d4000000000000000000000000000000000000000000000000000000008752600487016143e1565b03925af190811561047257612e697f0a1732153d4a8cd4fed1ee064d455ffc4550ad63847e795e5cc60c79e960ce569563ffffffff612e4760209a6001600160a01b03986128b797612e7d575b50612e41612e3b876142c8565b9861437e565b956142f0565b9390926040519889981688528a8c89015260a0604089015260a0880190613f6a565b931660608601528483036080860152614322565b6000612e8891614023565b8c612e2e565b013590508b806102e4565b8782526020822091601f198416815b818110612ee95750916001939185612d2a97969410612ecf575b505050811b018655612d24565b0135600019600384901b60f8161c191690558a8080612ec2565b91936020600181928787013581550195019201612ea8565b013590508a806102e4565b8382526020822091601f198416815b818110612f585750908460019594939210612f3e575b505050811b019055612cb7565b0135600019600384901b60f8161c19169055898080612f31565b91936020600181928787013581550195019201612f1b565b3461053757612fb3612f81366140f9565b612f8b8180614293565b612f996040849394016142c8565b612fa66020840184614293565b95909360608101906142f0565b50508115610bc157612fc861102b8580614343565b50612fd8602061132f8680614343565b94612fea63ffffffff61134688614d35565b50612ff486614d8d565b956000633b9aca004202946001600160401b03428704633b9aca0014421517159616915b81811061302157005b61302c81838b6144b0565b90606082016001600160401b03613042826142dc565b16151590816132a4575b5061327a578761326457608082016001600160401b0361306b826142dc565b1615159081613247575b5061321d5761308c61308683614c5b565b86614d60565b806000526000602052878c888c6040600020541580613204575b6130ba575b50505050506001915001613018565b6000936001600160a01b03936130d6886131129a9588956145ca565b96819688946040519c8d96879586937f5c4a461c0000000000000000000000000000000000000000000000000000000085528b6004860161477f565b0393165af1918215610472578b6001976000946131bb575b5061316184957f750f9e106a5ba29e7605ae8a4f82d3d771c6a161196fe496eaf436173649392d949550604051938493878561477f565b0390a18151613176575b5050878c888c6130ab565b6131a1827fdc54d6fa75b81ef04ee8e27b86d4deabbc0dbc79d0b30f70349d335fc29cf76494614e13565b6131b0604051928392836145a5565b0390a18b808061316b565b6131fc613161917f750f9e106a5ba29e7605ae8a4f82d3d771c6a161196fe496eaf436173649392d95963d8091833e6131f48183614023565b810190614721565b94935061312a565b856000526000602052600160f81b6040600020556130a6565b7fa48212700000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160401b03915061325a906142dc565b168410158c613075565b634e487b7160e01b600052601160045260246000fd5b7fa9cfb7050000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160401b0391506132b7906142dc565b164310158c61304c565b34610537576132cf366140c6565b60208101906132de8282614343565b359160058310156105375760026000930361124a57613305612c17602061132f8486614343565b916133e061333b61331b602061132f8686614343565b63ffffffff16600052600460205263ffffffff60406000205460481c1690565b613344836142c8565b94604051956bffffffffffffffffffffffff199060601b16602087015260148652613370603487614023565b6133b2604085019661338288876142f0565b909163ffffffff6040519661339688613fed565b600188521660208701528a60408701526060860152369161415d565b60808301526133c3608085016142dc565b6133d060608601866142f0565b916124f6604061132f8a8a614343565b15613924576133ed6148f6565b936133f88383614343565b9463ffffffff811695868352600560205260408320813560058110156139205760ff8019835416911617815561344f6134336020840161437e565b825464ffffffff00191660089190911b64ffffffff0016178255565b61348261345e6040840161437e565b825468ffffffff0000000000191660289190911b68ffffffff000000000016178255565b6001810161349360608401846142f0565b906001600160401b03821161390c576134b0826102b78554613f30565b8690601f83116001146138a157826134f59593600295936134e6938b926138965750508160011b916000199060031b1c19161790565b90555b019160808101906142f0565b906001600160401b03821161388257613512826102b78554613f30565b8490601f831160011461381e576135409291869183612f015750508160011b916000199060031b1c19161790565b90555b61354d8484614343565b6040516020810191602083528035600581101561381a578261068c81936135806135ee94604061360e9a99980190614044565b63ffffffff61359160208301613f1f565b16606084015263ffffffff6135a860408301613f1f565b1660808401526135dc6135d16135c160608401846144db565b60a08088015260e0870191614322565b9160808101906144db565b848303603f190160c086015290614322565b5190206135fa82614ffa565b8452836020526040842055612d37846142c8565b6001600160a01b0361361f836142c8565b1690613630602061132f8686614343565b91613640604061132f8787614343565b9061365861364e8787614343565b60808101906142f0565b949061366489886142f0565b61367060a08a016142c8565b92853b15613816579287969594919287938e956040519b8c998a9889977f13312a7e00000000000000000000000000000000000000000000000000000000895263ffffffff166004890152602488015263ffffffff1660448701526064860160c0905260c48601906136e192614322565b906003198583030160848601526136f792614322565b906001600160a01b031660a483015203925af18015613809576137f9575b5050613720816142c8565b9161372b8183614343565b60608101613738916142f0565b9490926137458382614343565b6040016137519061437e565b9261375c9082614343565b6020016137689061437e565b91613772916142f0565b919093604051966001600160a01b0388971687528860208801526040870160c0905260c08701906137a292614322565b9263ffffffff16606086015263ffffffff16608085015283820360a08501526137ca92614322565b037f7068ab3390ff136464b6c20a260d01fe69dc9db864fd2b3731705940a126e15191a1604051908152602090f35b61380291614023565b8480613715565b50604051903d90823e3d90fd5b8780fd5b8580fd5b8386526020862091601f198416875b81811061386a5750908460019594939210613850575b505050811b019055613543565b0135600019600384901b60f8161c19169055898080613843565b9193602060018192878701358155019501920161382d565b602485634e487b7160e01b81526041600452fd5b013590508e806102e4565b8388526020882091601f198416895b8181106138f457509260019285926134f5989660029896106138da575b505050811b0190556134e9565b0135600019600384901b60f8161c191690558d80806138cd565b919360206001819287870135815501950192016138b0565b602487634e487b7160e01b81526041600452fd5b8480fd5b600484630a104c9960e11b8152fd5b34610537576040366003190112610537576004356001600160401b03811161053757613963903690600401614099565b90602435916001600160a01b038316809303610537576001600160a01b036040518284823760208184810160018152030190205416613a0e577fa606f7f224af6d2a96bcbabbbbdaa76e2ec79197060291ceabedb9b69ceb479a926040518284823760208184810160018152030190206001600160a01b0382166001600160a01b0319825416179055613a03604051938493604085526040850191614322565b9060208301520390a1005b7f0c7cc9b90000000000000000000000000000000000000000000000000000000060005260046000fd5b346105375760203660031901126105375763ffffffff613a56613f0c565b16600052600260205261070c611c6e613a79604060002060405192838092613f6a565b604051918291602083526020830190614074565b346105375760203660031901126105375763ffffffff613aab613f0c565b16600052600560205263ffffffff604060002061070c6002613b30835493613af860405191613ae883613ae18160018501613f6a565b0384614023565b613ae16040518096819301613f6a565b6040519585613b0b8860ff819916614044565b818160081c16602088015260281c16604086015260a0606086015260a0850190614074565b908382036080850152614074565b3461053757613b4c36613ed9565b613b568180614293565b613b62604084016142c8565b90613b706020850185614293565b613b8d613b82608088969496016142dc565b9660608101906142f0565b90968415610bc15761134697602091613ba961102b8a80614343565b9060008a613bca63ffffffff613bc38861132f8580614343565b9e8f614d35565b938a600181148414613ec65750611eaa61137b613be79380614343565b925b613c306001600160a01b03613bfd83614baa565b16946040519088820152878152613c15604082614023565b60405190600160f81b8983015288825261140f604083614023565b03925af190811561047257600091613ea7575b501561107257613c5286614d8d565b956000633b9aca004202946001600160401b03428704633b9aca0014421517159616915b818110613c7f57005b613c8a81838b6144b0565b90606082016001600160401b03613ca0826142dc565b1615159081613e8a575b5061327a578761326457608082016001600160401b03613cc9826142dc565b1615159081613e6d575b5061321d57613ce461308683614c5b565b806000526000602052878c888c6040600020541580613e54575b613d12575b50505050506001915001613c76565b6000936001600160a01b0393613d2e88613d6a9a9588956145ca565b96819688946040519c8d96879586937f087cca7f0000000000000000000000000000000000000000000000000000000085528b6004860161477f565b0393165af1918215610472578b600197600094613e13575b50613db984957f2ae6b88938c4134c3a165b9073ed03a3c043905f7b942f2eddb33745e14fecb0949550604051938493878561477f565b0390a18151613dce575b5050878c888c613d03565b613df9827fdc54d6fa75b81ef04ee8e27b86d4deabbc0dbc79d0b30f70349d335fc29cf76494614e13565b613e08604051928392836145a5565b0390a18b8080613dc3565b613e4c613db9917f2ae6b88938c4134c3a165b9073ed03a3c043905f7b942f2eddb33745e14fecb095963d8091833e6131f48183614023565b949350613d82565b856000526000602052600160f81b604060002055613cfe565b6001600160401b039150613e80906142dc565b168410158c613cd3565b6001600160401b039150613e9d906142dc565b164310158c613caa565b613ec0915060203d602011611592576115848183614023565b87613c43565b611eaa90613ed393614cab565b92613be9565b602060031982011261053757600435906001600160401b0382116105375760a09082900360031901126105375760040190565b6004359063ffffffff8216820361053757565b359063ffffffff8216820361053757565b90600182811c92168015613f60575b6020831014613f4a57565b634e487b7160e01b600052602260045260246000fd5b91607f1691613f3f565b60009291815491613f7a83613f30565b8083529260018116908115613fd05750600114613f9657505050565b60009081526020812093945091925b838310613fb6575060209250010190565b600181602092949394548385870101520191019190613fa5565b915050602093945060ff929192191683830152151560051b010190565b60a081019081106001600160401b038211176104f757604052565b608081019081106001600160401b038211176104f757604052565b90601f801991011681019081106001600160401b038211176104f757604052565b9060058210156110ad5752565b60005b8381106140645750506000910152565b8181015183820152602001614054565b9060209161408d81518092818552858086019101614051565b601f01601f1916010190565b9181601f84011215610537578235916001600160401b038311610537576020838186019501011161053757565b602060031982011261053757600435906001600160401b0382116105375760c09082900360031901126105375760040190565b602060031982011261053757600435906001600160401b0382116105375760809082900360031901126105375760040190565b600435906001600160a01b038216820361053757565b6001600160401b0381116104f757601f01601f191660200190565b92919261416982614142565b916141776040519384614023565b829481845281830111610537578281602093846000960137010152565b9080601f83011215610537578160206141af9335910161415d565b90565b602060031982011261053757600435906001600160401b0382116105375760409082900360031901126105375760040190565b9060048210156110ad5752565b602060031982011261053757600435906001600160401b0382116105375760609082900360031901126105375760040190565b35906001600160401b038216820361053757565b6020815263ffffffff825116602082015263ffffffff602083015116604082015260a06001600160401b03608061427e604086015184606087015260c0860190614074565b94826060820151168286015201511691015290565b903590601e198136030182121561053757018035906001600160401b03821161053757602001918160051b3603831361053757565b356001600160a01b03811681036105375790565b356001600160401b03811681036105375790565b903590601e198136030182121561053757018035906001600160401b0382116105375760200191813603831361053757565b908060209392818452848401376000828201840152601f01601f1916010190565b903590609e1981360301821215610537570190565b60043563ffffffff811681036105375790565b60243563ffffffff811681036105375790565b3563ffffffff811681036105375790565b601f821161439c57505050565b6000526020600020906020601f840160051c830193106143d7575b601f0160051c01905b8181106143cb575050565b600081556001016143c0565b90915081906143b7565b939260609363ffffffff6001600160a01b039481614416959a999a168852166020870152608060408701526080860191614322565b9416910152565b9395949061445260809463ffffffff80956001600160a01b03829516895216602088015260a0604088015260a0870190613f6a565b9616606085015216910152565b60409063ffffffff6141af95931681528160208201520191614322565b926144169063ffffffff6060946001600160a01b038295999899168752166020860152608060408601526080850190613f6a565b90821015611599576141af9160051b810190614343565b51906001600160401b038216820361053757565b9035601e19823603018112156105375701602081359101916001600160401b03821161053757813603831361053757565b9063ffffffff61451b83613f1f565b16815263ffffffff61452f60208401613f1f565b16602082015260806001600160401b0361457e8261456461455360408801886144db565b60a0604089015260a0880191614322565b958361457260608301614225565b16606087015201614225565b1691015290565b906001600160a01b0361441660209295949560408552604085019061450c565b90916145bc6141af9360408452604084019061450c565b916020818403910152614074565b90821015611599576145e19160051b8101906142f0565b9091565b926040926144169161460a6001600160a01b039498979860608852606088019061450c565b918683036020880152614322565b908160609103126105375760405190606082018281106001600160401b038211176104f75761465a9160409182528051845260208101516020850152016144c7565b604082015290565b6001600160a01b031680156146f2576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b602081830312610537578051906001600160401b038211610537570181601f8201121561053757805161475381614142565b926147616040519485614023565b81845260208284010111610537576141af9160208085019101614051565b6001600160a01b0361479f6141af9694959360608452606084019061450c565b941660208201526040818503910152614322565b63ffffffff16600052600460205260406000205460ff811660048110156110ad576003036110835760081c63ffffffff1690565b90816020910312610537575180151581036105375790565b9491926141af96946001600160401b036148449563ffffffff6148369516895216602088015260a0604088015260a0870191614322565b908482036060860152614074565b916080818403910152614074565b6000906148af60209694959761489861487c6001600160a01b0361487586614baa565b1697614ffa565b91604051928a840152898352614893604084614023565b615020565b90604051918983015288825261140f604083614023565b03925af1908115610472576000916148c5575090565b6141af915060203d602011611592576115848183614023565b63ffffffff60019116019063ffffffff821161326457565b7fc031b20c2b3a8a1fbfa9cc022aa3477489d4b8c91f0e667e900f5ad44daf8b6d600052600060205263ffffffff6040600020541663ffffffff614939826148de565b7fc031b20c2b3a8a1fbfa9cc022aa3477489d4b8c91f0e667e900f5ad44daf8b6d6000908152602052167fa948e29ac0e6a6a5e3c647a07a0505170c972dd4960cbe194aee77626bb52b585590565b906040519061499682613fed565b80549160ff831660058110156110ad576149f8614a029363ffffffff614a08966002948652818160081c16602087015260281c1660408501526040516149e381611c6e8160018601613f6a565b6060850152611c6e6040518094819301613f6a565b6080820152615020565b91614ffa565b6000526000602052604060002055565b7f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a600052600060205263ffffffff6040600020541663ffffffff614a5b826148de565b7f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a6000908152602052167f24072874bb11662934f0c68ca2659a14efae71555bb48eba2450fe6433183f955590565b6020949293956148af63ffffffff6000935460081c1691614adc6001600160a01b03614ad585614baa565b169661508f565b906040519189830152888252614af3604083614023565b60405163ffffffff60608b830193614b0c8582516141e5565b828d8201511660408501528260408201511682850152015116608082015260808152614b3960a082614023565b51902090604051918983015288825261140f604083614023565b90614a089060405163ffffffff602082019254614b738460ff83166141e5565b818160081c166040840152818160281c16606084015260481c16608082015260808152614ba160a082614023565b5190209161508f565b63ffffffff1660005260036020526001600160a01b03604060002054168015614bd05790565b7fb6c71f7d0000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303614c2d57565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b604051614c788161068c602082019460208652604083019061450c565b51902090565b906040519063ffffffff602083019360048552166040830152606082015260608152614c78608082614023565b60405190816020810193806040830160208752526060820160608260051b8401019184600090609e1981360301935b838310614cf9575050505050614c78925003601f198101835282614023565b919395509193605f19888203018252863586811215610537576020614d236001938683940161450c565b98019201930190959391879593614cda565b63ffffffff166000526005602052604060002060ff81541660058110156110ad57600303611d995790565b906040519063ffffffff602083019360058552166040830152606082015260608152614c78608082614023565b63ffffffff1660005260066020526001600160a01b03604060002054168015614db35790565b7fc6830cff0000000000000000000000000000000000000000000000000000000060005260046000fd5b611eaa614de992614c5b565b806000526000602052600160f81b60406000205403611f0557600052600060205260006040812055565b908160005260006020526040600020548015614eaf57600160f81b03614e85576001600160f81b0390604051614e6a60208281614e598183019687815193849201614051565b81010301601f198101835282614023565b51902016600160f81b17906000526000602052604060002055565b7f5c6d77110000000000000000000000000000000000000000000000000000000060005260046000fd5b7f53a55dcb0000000000000000000000000000000000000000000000000000000060005260046000fd5b9190604051602081019180604083016020855252606082019060608160051b8401019580926000915b838310614f37575050505050614f2a816001600160f81b03949503601f198101835282614023565b51902016600160f81b1790565b9091929397602080614f5e600193605f198a8203018752614f588d876144db565b90614322565b9a019301930191939290614f02565b6001600160f81b0391614f2a602060405183819483830196873781016000838201520301601f198101835282614023565b60405163ffffffff60208201926000845216604082015260408152614c78606082614023565b906001600160401b036040519163ffffffff60208401946001865216604084015216606082015260608152614c78608082614023565b60405163ffffffff60208201926003845216604082015260408152614c78606082614023565b604051614c788161068c602082019460208652615041604084018251614044565b63ffffffff602082015116606084015263ffffffff6040820151166080840152608061507b606083015160a08087015260e0860190614074565b910151838203603f190160c0850152614074565b60405163ffffffff60208201926002845216604082015260408152614c78606082614023565b60ff60008051602061518d8339815191525460401c16156150d257565b7fd7e6bcf80000000000000000000000000000000000000000000000000000000060005260046000fd5b9061513b575080511561511157805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b81511580615183575b61514c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b1561514456fef0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220587a41eff529d00dbece673951e108a71f34d6c6042ef0b5f8bded43eb79891e64736f6c634300081b0033
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c80630e04968414613b3e578063113a1b7014613a8d5780631296c14814613a3857806318c19870146139335780632b2c5463146132c15780634127910814612f70578063441fd11514612bf95780634f1ef2861461295757806352d1902d146128c25780635a06a1881461273d5780635f5d288e146126fd5780636415d1a3146123ab57806370a31901146122ce578063715018a61461223557806382a09c151461204a578063839df9451461201e57806383c808ff14611f2f5780638548fbbe14611e665780638da5cb5b14611e20578063990491a514611daa578063999d5c6b14611b585780639aa0346f1461172d5780639f18077b1461163a578063ad3cb1cc146115db578063afc3619b146112d3578063b1892e401461126d578063b69562bd146110c3578063baec252714610f04578063c4d66de814610beb578063c8982e1514610a6b578063db305c1c1461097b578063de844ebc1461093b578063dea5a7231461090c578063dee97dc614610796578063e5cbff7914610567578063f2fde38b1461053c5763fed12cbf146101b357600080fd5b34610537576101c1366140f9565b6001600160a01b0360206101d583806142f0565b9190826040519384928337810160018152030190205416801561050d577f9b9820486a05c0193efb214c6c2ba8fce02c5a5c84aa057f8199c99f13ff939b600052600060205263ffffffff604060002054169063ffffffff610236836148de565b7f9b9820486a05c0193efb214c6c2ba8fce02c5a5c84aa057f8199c99f13ff939b6000908152602052167fa17c46f2d2a87aa05f956999001178d4f3a177d856047a83ccebd64d7a2ef49d5561028c83806142f0565b8360005260026020526040600020916001600160401b0382116104f7576102bd826102b78554613f30565b8561438f565b600090601f831160011461048957926102f98361038794610399979460609760009261047e575b50508160011b916000199060031b1c19161790565b90555b84600052600360205260406000206001600160a01b0382166001600160a01b0319825416179055600061033260208801886142f0565b61034260408a949394018a6142f0565b9790604051988997889687957fae3fee350000000000000000000000000000000000000000000000000000000087528d60048801528b60248801526064870191614322565b84810360031901604486015291614322565b03925af1908115610472576020937f6e071f9d82ad3d0aaae325775210a4689898ec9475243a1a0692d374a6ad1f469261041c92600091610443575b5080516103e186614f9e565b600052600087526040600020556104096001600160401b036040888401519301511686614fc4565b60005260008652604060002055806142f0565b610433604051928392604084526040840191614322565b84868301520390a1604051908152f35b610465915060603d60601161046b575b61045d8183614023565b810190614618565b386103d5565b503d610453565b6040513d6000823e3d90fd5b0135905038806102e4565b8382526020822091601f198416815b8181106104df5750936103999693606096936001938361038798106104c5575b505050811b0190556102fc565b0135600019600384901b60f8161c191690553880806104b8565b91936020600181928787013581550195019201610498565b634e487b7160e01b600052604160045260246000fd5b7faa478af90000000000000000000000000000000000000000000000000000000060005260046000fd5b600080fd5b346105375760203660031901126105375761056561055861412c565b610560614bfa565b614662565b005b3461053757608036600319011261053757610580613f0c565b6024356001600160401b03811680910361053757604435916001600160401b038316809303610537576064356001600160401b038111610537576105c8903690600401614099565b939092600060806040516105db81613fed565b82815282602082015260606040820152826060820152015281158061078e575b610764576106258363ffffffff1660005260066020526001600160a01b0360406000205416331490565b1561073a576106676106a39463ffffffff61063f86614d35565b5460281c16966040519761065289613fed565b63ffffffff871689526020890152369161415d565b604086015260608501526080840152604051602081019061069a8161068c8785614239565b03601f198101835282614023565b51902090614c7e565b908160005260006020526040600020546107105761070c916000526000602052600160f81b6040600020557ff58a2d54b6bf8f57965fae5cadacc16f93672604359e3623141d22248ac71a75604051806106fd8482614239565b0390a160405191829182614239565b0390f35b7fa29bd6ea0000000000000000000000000000000000000000000000000000000060005260046000fd5b7fcc12cef60000000000000000000000000000000000000000000000000000000060005260046000fd5b7fddd92f790000000000000000000000000000000000000000000000000000000060005260046000fd5b5080156105fb565b34610537576108146107a7366141f2565b606060006001600160a01b036107c46107bf8561437e565b614baa565b166107ce8461437e565b6107db60208601866142f0565b939091604051978895869485937ff67f54fa0000000000000000000000000000000000000000000000000000000085526004850161445f565b03925af1908115610472577f078276040a4f9f4dea1214e38413d6bac929b39330be19599176564d23d5ef41926000926108de575b506108aa6001600160401b039183516108696108648361437e565b614f9e565b60005260006020526040600020556020840151610897604061088a8461437e565b9601958587511690614fc4565b600052600060205260406000205561437e565b915116906108d9604051928392839092916001600160401b0360209163ffffffff604085019616845216910152565b0390a1005b6001600160401b039192506109046108aa9160603d60601161046b5761045d8183614023565b929150610849565b3461053757602036600319011261053757602061092a6107bf613f0c565b6001600160a01b0360405191168152f35b346105375760203660031901126105375763ffffffff610959613f0c565b16600052600660205260206001600160a01b0360406000205416604051908152f35b346105375760603660031901126105375760206000610a1761099b614a18565b9163ffffffff8316928382526004855260408220916109d76109bb614358565b845464ffffffff00191660089190911b64ffffffff0016178455565b50815460ff19166001178255610a126109ee61436b565b835468ffffffff0000000000191660289190911b68ffffffff000000000016178355565b614b53565b7f5c19396f17b2d5b8ebfa9d37569101115f64e85557fe202593aa3e5555bad05d6060610a42614358565b63ffffffff610a4f61436b565b81604051938785521687840152166040820152a1604051908152f35b3461053757610a79366141f2565b60208101610a878183614293565b92905060028310610bc157604081019260005b818110610aee5783610adb84610ad5610acf610abf610ab98b85614293565b90614ed9565b94610ac98461437e565b93614293565b90614cab565b90614d60565b6000526000602052604060002055600080f35b610b2e610b0582610aff8787614293565b906144b0565b610b1983610b138988614293565b906145ca565b929091610ad5610b288861437e565b91614c5b565b60005260006020526040600020549182158015610bb4575b610b8a57610b5391614f6d565b03610b6057600101610a9a565b7f59c3580a0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f2430f4030000000000000000000000000000000000000000000000000000000060005260046000fd5b50600160f81b8314610b46565b7f5458d3430000000000000000000000000000000000000000000000000000000060005260046000fd5b3461053757602036600319011261053757610c0461412c565b60008051602061518d833981519152549060ff8260401c1615916001600160401b03811680159081610efc575b6001149081610ef2575b159081610ee9575b50610e775767ffffffffffffffff19811660011760008051602061518d8339815191525582610ebc575b5060008051602061518d8339815191525460ff8160401c1615916001600160401b03821680159081610eb4575b6001149081610eaa575b159081610ea1575b50610e775767ffffffffffffffff19821660011760008051602061518d83398151915255610ceb9183610e4a575b50610ce36150b5565b6105606150b5565b610cf36150b5565b6000602081905260017fa17c46f2d2a87aa05f956999001178d4f3a177d856047a83ccebd64d7a2ef49d8190557fa948e29ac0e6a6a5e3c647a07a0505170c972dd4960cbe194aee77626bb52b588190557f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a9091527f24072874bb11662934f0c68ca2659a14efae71555bb48eba2450fe6433183f9555610dee575b610d9557005b68ff00000000000000001960008051602061518d833981519152541660008051602061518d833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b68ff00000000000000001960008051602061518d833981519152541660008051602061518d833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1610d8f565b68ffffffffffffffffff1916680100000000000000011760008051602061518d8339815191525584610cda565b7ff92ee8a90000000000000000000000000000000000000000000000000000000060005260046000fd5b90501585610cac565b303b159150610ca4565b849150610c9a565b68ffffffffffffffffff1916680100000000000000011760008051602061518d8339815191525582610c6d565b90501584610c43565b303b159150610c3b565b849150610c31565b3461053757610f1236613ed9565b63ffffffff610f208261437e565b1660005260046020526040600020805460ff811660048110156110ad576001036110835763ffffffff610f528461437e565b8160405193610f6085614008565b60028552818160281c16602086015260081c166040840152166060820152610fb1610f8d606085016142dc565b91610f9b60408601866142f0565b602087019491610faa8661437e565b9287614aaa565b15611072577fdb439789af7a0ed4968cc1f35b0c7dfd9c878c6508bd7fd48053e87df31231d09261101e610ff261103093600360ff1987541617865561437e565b84546cffffffff000000000000000000191660489190911b6cffffffff00000000000000000016178455565b61102b83610a128361437e565b61437e565b90546040805163ffffffff9384168152600883901c84166020820152602883901c84169181019190915260489190911c909116606082015280608081016108d9565b630a104c9960e11b60005260046000fd5b7f8ca989900000000000000000000000000000000000000000000000000000000060005260046000fd5b634e487b7160e01b600052602160045260246000fd5b3461053757604036600319011261053757600063ffffffff6110e3614358565b168152600560205260408120805460ff811660058110156112595760030361124a5763ffffffff6111179160081c166147b3565b50805460ff191660041781556111348161112f614358565b614988565b63ffffffff611141614358565b1682526006602052816001600160a01b0360408220541691611161614358565b92602435936001600160a01b038516850361124657813b15611246576040517fc2c0030b00000000000000000000000000000000000000000000000000000000815263ffffffff9190911660048201526001600160a01b03949094166024850152828460448183855af190811561123b577f5d4b57424fd8ef7d85bed4d570d10b0bf5d38ef1936569ba4ca1f62ff78836e5946001946112259361122b575b505061120a614358565b9063ffffffff845460281c169160405195869501918561447c565b0390a180f35b61123491614023565b8686611200565b6040513d85823e3d90fd5b8380fd5b600483634b6848a360e11b8152fd5b602484634e487b7160e01b81526021600452fd5b346105375760203660031901126105375763ffffffff61128b613f0c565b166000526004602052608060406000205463ffffffff604051916112b28360ff83166141e5565b818160081c166020840152818160281c16604084015260481c166060820152f35b34610537576112e136613ed9565b6112eb8180614293565b8092915015610bc1576112fe8180614293565b156115995761102b8161131092614343565b9161131b8280614293565b1561159957602061132f8261133593614343565b0161437e565b61135063ffffffff61134686614d35565b5460081c166147b3565b90600183036115af576113638480614293565b9190911561159957610ad561137b8361138094614343565b614c5b565b9061138e6020850185614293565b9190911561159957611445926113af6113a9846020956142f0565b90614f6d565b915b60006113bf606089016142dc565b916113cd60408a018a6142f0565b9790956001600160a01b036113e184614baa565b169560405190898201528881526113f9604082614023565b604051918983015288825261140f604083614023565b604051998a98899788967fa9f9396e000000000000000000000000000000000000000000000000000000008852600488016147ff565b03925af19081156104725760009161156a575b5015611072579061146883614d8d565b906001600160a01b0360009216906020810160808201935b85811061148957005b61149781610aff8580614293565b906114a28289614ddd565b6114b081610b138587614293565b92906114bb886142c8565b91873b156105375760006114ff93604051809581927ff33d7175000000000000000000000000000000000000000000000000000000008352898787600486016145e5565b0381838c5af18015610472576001957f58ecb5cdbc94a25c1a782bb33f66684c1804b56e0d8b3a666160f6e5896f311e9461155092611559575b506115438b6142c8565b90604051948594856145e5565b0390a101611480565b600061156491614023565b8d611539565b61158c915060203d602011611592575b6115848183614023565b8101906147e7565b84611458565b503d61157a565b634e487b7160e01b600052603260045260246000fd5b611445916115c6602092610ad5610acf8880614293565b6115d5610ab984880188614293565b916113b1565b346105375760003660031901126105375761070c60408051906115fe8183614023565b600582527f352e302e30000000000000000000000000000000000000000000000000000000602083015251918291602083526020830190614074565b34610537576040366003190112610537576004356001600160401b03811161053757806004019060a06003198236030112610537576024356001600160401b0381116105375761168e903690600401614194565b90815115610b8a57602401916116c86116a68461437e565b63ffffffff1660005260066020526001600160a01b0360406000205416331490565b1561073a5761171e826117196117108661170a6117057fdc54d6fa75b81ef04ee8e27b86d4deabbc0dbc79d0b30f70349d335fc29cf7649961437e565b614d35565b5061437e565b610ad585614c5b565b614e13565b6108d9604051928392836145a5565b346105375761173b366140f9565b6117458180614343565b61174e8161437e565b61175a6020830161437e565b61176b63ffffffff61134684614d35565b906001600160a01b0361177d83614baa565b16916117e360206040880194611792866142dc565b6040517fe9946fc300000000000000000000000000000000000000000000000000000000815263ffffffff861660048201526001600160401b03909116602482015292839190829081906044820190565b03915afa801561047257600090611b18575b6001600160401b03915016918215611aee57866118b863ffffffff60006001600160401b03956118ca61182d602097610ad58e614c5b565b6118436118398c6142dc565b97898101906142f0565b96906001600160a01b0361185686614baa565b1697604051938b8501528a845261186e604085614023565b6040519b8c9a8b998a987f3fd413de000000000000000000000000000000000000000000000000000000008a52166004890152166024870152608060448701526084860191614322565b83810360031901606485015290614074565b03925af190811561047257600091611acf575b5015611072576118f6846118f085614d8d565b94614ddd565b60808401906001600160401b0361190c836142dc565b161580611ab3575b610764576001600160401b03611929836142dc565b1615159182611a96575b5050611a6c5760608301906001600160401b0361194f836142dc565b1615159182611a43575b5050611a19576001600160a01b031691606001611975816142c8565b92803b15610537576119bc6000949185926040519687809481937fda6a79860000000000000000000000000000000000000000000000000000000083528960048401614585565b03925af1908115610472577f4493027da4552008217d5c8f83ace2a1a78d2ae45b427b49c0c363be9a2d7aea936119f892611a08575b506142c8565b906108d960405192839283614585565b6000611a1391614023565b846119f2565b7f12c51c640000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160401b03919250611a61611a5b83926142dc565b936142dc565b169116118480611959565b7f8551d2350000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160401b03919250611aaa906142dc565b16118580611933565b506001600160401b03611ac8606087016142dc565b1615611914565b611ae8915060203d602011611592576115848183614023565b866118dd565b7f9b6c9adc0000000000000000000000000000000000000000000000000000000060005260046000fd5b506020813d602011611b50575b81611b3260209383614023565b8101031261053757611b4b6001600160401b03916144c7565b6117f5565b3d9150611b25565b3461053757611b66366140f9565b63ffffffff611b748261437e565b166000526005602052604060002080549060ff821660058110156110ad57600203611d9957611ca063ffffffff8360081c16611baf816147b3565b63ffffffff611bbd8761437e565b16600052600660205263ffffffff604060002054956001600160a01b0387169682611c0b611bea8b61437e565b9663ffffffff16600052600460205263ffffffff60406000205460481c1690565b95604051926bffffffffffffffffffffffff199060601b16602084015260148352611c37603484614023565b8160405197611c4589613fed565b600389521660208801521660408601526060850152604051611c7581611c6e8160028b01613f6a565b0382614023565b6080850152611c86604089016142dc565b611c9360208a018a6142f0565b93909260281c1693614852565b1561107257805460ff19166003178155611cbd8161112f8561437e565b611cc68361437e565b611cd2606085016142c8565b90833b15610537576040517f423b7df600000000000000000000000000000000000000000000000000000000815263ffffffff9190911660048201526001600160a01b0391909116602482015260008160448183875af18015610472577f03c5f9b30a58d1ae49f1cff4d32c3906e7705104c0e815b97492af31137cb9fb946108d992611d6392611d88575061437e565b91805490604051948594600163ffffffff808660081c169560281c169301918661441d565b6000611d9391614023565b8661170a565b634b6848a360e11b60005260046000fd5b34610537576020366003190112610537576004356001600160401b0381116105375736602382011215610537576001600160a01b03611e0c6020611df98194369060248160040135910161415d565b8160405193828580945193849201614051565b810160018152030190205416604051908152f35b346105375760003660031901126105375760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b3461053757611e74366141b2565b60208101611e828183614293565b905060028110610bc15760005b818110611ec857611eb084611eaa610acf86610ac98461437e565b90614c7e565b6000526000602052600160f81b604060002055600080f35b611ee5611ed982610aff8688614293565b611eaa610b288761437e565b6000526000602052600160f81b60406000205403611f0557600101611e8f565b7f4d7cfc570000000000000000000000000000000000000000000000000000000060005260046000fd5b3461053757611f3d366140f9565b63ffffffff611f4b8261437e565b1660005260046020526040600020805460ff811660048110156110ad5760020361108357611fdc90611f7c8461437e565b9063ffffffff60405192611f8f84614008565b60038452818360281c166020850152818360081c16604085015216606083015263ffffffff611fc0604087016142dc565b91611fce60208801886142f0565b92909160481c169286614aaa565b15611072576110307fc382cf337d6f6a49bfb3fb8ec3fa62783704bd87aa72d534ff1b99195050aad892600360ff1984541617835561102b83610a128361437e565b346105375760203660031901126105375760043560005260006020526020604060002054604051908152f35b3461053757612058366140f9565b63ffffffff6120668261437e565b16600052600560205260406000209081549160ff831660058110156110ad57600303611d995761215e63ffffffff8460081c166120a2816147b3565b63ffffffff6120b08661437e565b16600052600660205263ffffffff604060002054966001600160a01b03881697826120dd611bea8a61437e565b95604051926bffffffffffffffffffffffff199060601b16602084015260148352612109603484614023565b816040519761211789613fed565b60048952166020880152166040860152606085015260405161214081611c6e8160028b01613f6a565b6080850152612151604088016142dc565b611c9360208901896142f0565b1561107257805460ff1916600417815561217b8161112f8461437e565b6121848261437e565b612190606084016142c8565b90843b15610537576040517f578392c500000000000000000000000000000000000000000000000000000000815263ffffffff9190911660048201526001600160a01b0391909116602482015260008160448183885af19384156104725761120a6001946108d9937ff55ea0b61aba75ba1463c3325f7b0a06baa2d96ee4a621a05dabdf03b489c41d97612224575061437e565b600061222f91614023565b8761170a565b346105375760003660031901126105375761224e614bfa565b60006001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610537576122dc366141b2565b6001600160a01b036122f06107bf8361437e565b166122fa8261437e565b61230760208401846142f0565b9092803b156105375761234e9360008094604051968795869485937fa4479b110000000000000000000000000000000000000000000000000000000085526004850161445f565b03925af18015610472577f2d86933ea68552f2484167a027c9e1a658fee909dffcc151fb2d4fde750311269260209261238b9261239a575061437e565b63ffffffff60405191168152a1005b60006123a591614023565b8461170a565b34610537576123b9366140c6565b63ffffffff6123c78261437e565b1660005260056020526040600020805460ff811660058110156110ad57600103611d995760081c63ffffffff16906123fe826147b3565b9263ffffffff61240d8261437e565b166000526006602052604060002054936124fc6001600160a01b038616946124c861245b61243a8661437e565b9263ffffffff16600052600460205263ffffffff60406000205460481c1690565b91604051986bffffffffffffffffffffffff199060601b1660208a01526014895261248760348a614023565b63ffffffff602087019961249b8b896142f0565b92909381604051976124ac89613fed565b600289521660208801521660408601526060850152369161415d565b60808201526124d9608085016142dc565b926124e760608601866142f0565b9060408701956124f68761437e565b93614852565b1561107257825460ff1916600317835561251685836142f0565b60028501916001600160401b0382116104f757612537826102b78554613f30565b600090601f83116001146126995761256792916000918361268e5750508160011b916000199060031b1c19161790565b90555b61259a6125768261437e565b845468ffffffff0000000000191660289190911b68ffffffff000000000016178455565b6125a78361112f8461437e565b6125b08261437e565b946125c46125bd8361437e565b91846142f0565b9190966125d360a086016142c8565b92873b1561053757600093612616916040519a8b9586957f5209209d000000000000000000000000000000000000000000000000000000008752600487016143e1565b038183885af19384156104725761266261265c6108d9947f958d927ded58a29a450e24013886756bcee58e1146c05e9d0c671e5003cf8d909860019861267d575061437e565b9261437e565b9063ffffffff855460081c169260405196879601918661441d565b600061268891614023565b8961170a565b0135905089806102e4565b8382526020822091601f198416815b8181106126e557509084600195949392106126cb575b505050811b01905561256a565b0135600019600384901b60f8161c191690558880806126be565b919360206001819287870135815501950192016126a8565b346105375760203660031901126105375763ffffffff61271b613f0c565b16600052600360205260206001600160a01b0360406000205416604051908152f35b346105375761274b366140c6565b612753614a18565b9063ffffffff821690816000526004602052604060002090604081019361277c6109bb8661437e565b825460ff191660021783556127936125768361437e565b60208201946127d06127a48761437e565b85546cffffffff000000000000000000191660489190911b6cffffffff00000000000000000016178555565b6128396127dc8461437e565b63ffffffff6127ea8461437e565b81604051936127f885614008565b600185521660208401521660408201526000606082015261281b608086016142dc565b61282860608701876142f0565b906128328b61437e565b9289614aaa565b156110725760209561288561287f6128796128b79461102b7f0a9d00e740d5a7292ecf25db89826a19ca7963a06c398a7f95947e84d1ce8f319988614b53565b9561437e565b9161437e565b9060405194859485929363ffffffff809296958160609581608089019a16885216602087015216604085015216910152565b0390a1604051908152f35b34610537576000366003190112610537576001600160a01b037f0000000000000000000000000e3949c6b4049b61be367826869fd300388d710016300361292d5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b7fe07c8dba0000000000000000000000000000000000000000000000000000000060005260046000fd5b60403660031901126105375761296b61412c565b6024356001600160401b0381116105375761298a903690600401614194565b6001600160a01b037f0000000000000000000000000e3949c6b4049b61be367826869fd300388d710016803014908115612bc4575b5061292d576129cc614bfa565b6001600160a01b038216916040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481875afa60009181612b90575b50612a295783634c9c8ce360e01b60005260045260246000fd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc859203612b635750813b15612b4f57806001600160a01b03197f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2815115612b1c5760008083602061056595519101845af43d15612b14573d91612af783614142565b92612b056040519485614023565b83523d6000602085013e6150fc565b6060916150fc565b505034612b2557005b7fb398979f0000000000000000000000000000000000000000000000000000000060005260046000fd5b634c9c8ce360e01b60005260045260246000fd5b7faa1d49a40000000000000000000000000000000000000000000000000000000060005260045260246000fd5b9091506020813d602011612bbc575b81612bac60209383614023565b8101031261053757519085612a0f565b3d9150612b9f565b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54161415836129bf565b3461053757612c0736613ed9565b60408101612c1c612c178261437e565b6147b3565b50612c256148f6565b9063ffffffff821691826000526005602052604060002091600160ff19845416178355612c546109bb8261437e565b6060850194612c6386826142f0565b60028601916001600160401b0382116104f757612c84826102b78554613f30565b600090601f8311600114612f0c57612cb4929160009183612f015750508160011b916000199060031b1c19161790565b90555b612cc460208201826142f0565b6001860195916001600160401b0382116104f757612cec82612ce68954613f30565b8961438f565b600090601f8311600114612e99579180612d2192612d2a9594600092612e8e5750508160011b916000199060031b1c19161790565b86555b84614988565b612d6683612d37836142c8565b9063ffffffff1660005260066020526001600160a01b03604060002091166001600160a01b0319825416179055565b6001600160a01b03612d77826142c8565b1692612d828361437e565b90612d8d88846142f0565b959091612d9c608086016142c8565b823b1561053757600094612de186926040519a8b97889687957f27e756d4000000000000000000000000000000000000000000000000000000008752600487016143e1565b03925af190811561047257612e697f0a1732153d4a8cd4fed1ee064d455ffc4550ad63847e795e5cc60c79e960ce569563ffffffff612e4760209a6001600160a01b03986128b797612e7d575b50612e41612e3b876142c8565b9861437e565b956142f0565b9390926040519889981688528a8c89015260a0604089015260a0880190613f6a565b931660608601528483036080860152614322565b6000612e8891614023565b8c612e2e565b013590508b806102e4565b8782526020822091601f198416815b818110612ee95750916001939185612d2a97969410612ecf575b505050811b018655612d24565b0135600019600384901b60f8161c191690558a8080612ec2565b91936020600181928787013581550195019201612ea8565b013590508a806102e4565b8382526020822091601f198416815b818110612f585750908460019594939210612f3e575b505050811b019055612cb7565b0135600019600384901b60f8161c19169055898080612f31565b91936020600181928787013581550195019201612f1b565b3461053757612fb3612f81366140f9565b612f8b8180614293565b612f996040849394016142c8565b612fa66020840184614293565b95909360608101906142f0565b50508115610bc157612fc861102b8580614343565b50612fd8602061132f8680614343565b94612fea63ffffffff61134688614d35565b50612ff486614d8d565b956000633b9aca004202946001600160401b03428704633b9aca0014421517159616915b81811061302157005b61302c81838b6144b0565b90606082016001600160401b03613042826142dc565b16151590816132a4575b5061327a578761326457608082016001600160401b0361306b826142dc565b1615159081613247575b5061321d5761308c61308683614c5b565b86614d60565b806000526000602052878c888c6040600020541580613204575b6130ba575b50505050506001915001613018565b6000936001600160a01b03936130d6886131129a9588956145ca565b96819688946040519c8d96879586937f5c4a461c0000000000000000000000000000000000000000000000000000000085528b6004860161477f565b0393165af1918215610472578b6001976000946131bb575b5061316184957f750f9e106a5ba29e7605ae8a4f82d3d771c6a161196fe496eaf436173649392d949550604051938493878561477f565b0390a18151613176575b5050878c888c6130ab565b6131a1827fdc54d6fa75b81ef04ee8e27b86d4deabbc0dbc79d0b30f70349d335fc29cf76494614e13565b6131b0604051928392836145a5565b0390a18b808061316b565b6131fc613161917f750f9e106a5ba29e7605ae8a4f82d3d771c6a161196fe496eaf436173649392d95963d8091833e6131f48183614023565b810190614721565b94935061312a565b856000526000602052600160f81b6040600020556130a6565b7fa48212700000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160401b03915061325a906142dc565b168410158c613075565b634e487b7160e01b600052601160045260246000fd5b7fa9cfb7050000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160401b0391506132b7906142dc565b164310158c61304c565b34610537576132cf366140c6565b60208101906132de8282614343565b359160058310156105375760026000930361124a57613305612c17602061132f8486614343565b916133e061333b61331b602061132f8686614343565b63ffffffff16600052600460205263ffffffff60406000205460481c1690565b613344836142c8565b94604051956bffffffffffffffffffffffff199060601b16602087015260148652613370603487614023565b6133b2604085019661338288876142f0565b909163ffffffff6040519661339688613fed565b600188521660208701528a60408701526060860152369161415d565b60808301526133c3608085016142dc565b6133d060608601866142f0565b916124f6604061132f8a8a614343565b15613924576133ed6148f6565b936133f88383614343565b9463ffffffff811695868352600560205260408320813560058110156139205760ff8019835416911617815561344f6134336020840161437e565b825464ffffffff00191660089190911b64ffffffff0016178255565b61348261345e6040840161437e565b825468ffffffff0000000000191660289190911b68ffffffff000000000016178255565b6001810161349360608401846142f0565b906001600160401b03821161390c576134b0826102b78554613f30565b8690601f83116001146138a157826134f59593600295936134e6938b926138965750508160011b916000199060031b1c19161790565b90555b019160808101906142f0565b906001600160401b03821161388257613512826102b78554613f30565b8490601f831160011461381e576135409291869183612f015750508160011b916000199060031b1c19161790565b90555b61354d8484614343565b6040516020810191602083528035600581101561381a578261068c81936135806135ee94604061360e9a99980190614044565b63ffffffff61359160208301613f1f565b16606084015263ffffffff6135a860408301613f1f565b1660808401526135dc6135d16135c160608401846144db565b60a08088015260e0870191614322565b9160808101906144db565b848303603f190160c086015290614322565b5190206135fa82614ffa565b8452836020526040842055612d37846142c8565b6001600160a01b0361361f836142c8565b1690613630602061132f8686614343565b91613640604061132f8787614343565b9061365861364e8787614343565b60808101906142f0565b949061366489886142f0565b61367060a08a016142c8565b92853b15613816579287969594919287938e956040519b8c998a9889977f13312a7e00000000000000000000000000000000000000000000000000000000895263ffffffff166004890152602488015263ffffffff1660448701526064860160c0905260c48601906136e192614322565b906003198583030160848601526136f792614322565b906001600160a01b031660a483015203925af18015613809576137f9575b5050613720816142c8565b9161372b8183614343565b60608101613738916142f0565b9490926137458382614343565b6040016137519061437e565b9261375c9082614343565b6020016137689061437e565b91613772916142f0565b919093604051966001600160a01b0388971687528860208801526040870160c0905260c08701906137a292614322565b9263ffffffff16606086015263ffffffff16608085015283820360a08501526137ca92614322565b037f7068ab3390ff136464b6c20a260d01fe69dc9db864fd2b3731705940a126e15191a1604051908152602090f35b61380291614023565b8480613715565b50604051903d90823e3d90fd5b8780fd5b8580fd5b8386526020862091601f198416875b81811061386a5750908460019594939210613850575b505050811b019055613543565b0135600019600384901b60f8161c19169055898080613843565b9193602060018192878701358155019501920161382d565b602485634e487b7160e01b81526041600452fd5b013590508e806102e4565b8388526020882091601f198416895b8181106138f457509260019285926134f5989660029896106138da575b505050811b0190556134e9565b0135600019600384901b60f8161c191690558d80806138cd565b919360206001819287870135815501950192016138b0565b602487634e487b7160e01b81526041600452fd5b8480fd5b600484630a104c9960e11b8152fd5b34610537576040366003190112610537576004356001600160401b03811161053757613963903690600401614099565b90602435916001600160a01b038316809303610537576001600160a01b036040518284823760208184810160018152030190205416613a0e577fa606f7f224af6d2a96bcbabbbbdaa76e2ec79197060291ceabedb9b69ceb479a926040518284823760208184810160018152030190206001600160a01b0382166001600160a01b0319825416179055613a03604051938493604085526040850191614322565b9060208301520390a1005b7f0c7cc9b90000000000000000000000000000000000000000000000000000000060005260046000fd5b346105375760203660031901126105375763ffffffff613a56613f0c565b16600052600260205261070c611c6e613a79604060002060405192838092613f6a565b604051918291602083526020830190614074565b346105375760203660031901126105375763ffffffff613aab613f0c565b16600052600560205263ffffffff604060002061070c6002613b30835493613af860405191613ae883613ae18160018501613f6a565b0384614023565b613ae16040518096819301613f6a565b6040519585613b0b8860ff819916614044565b818160081c16602088015260281c16604086015260a0606086015260a0850190614074565b908382036080850152614074565b3461053757613b4c36613ed9565b613b568180614293565b613b62604084016142c8565b90613b706020850185614293565b613b8d613b82608088969496016142dc565b9660608101906142f0565b90968415610bc15761134697602091613ba961102b8a80614343565b9060008a613bca63ffffffff613bc38861132f8580614343565b9e8f614d35565b938a600181148414613ec65750611eaa61137b613be79380614343565b925b613c306001600160a01b03613bfd83614baa565b16946040519088820152878152613c15604082614023565b60405190600160f81b8983015288825261140f604083614023565b03925af190811561047257600091613ea7575b501561107257613c5286614d8d565b956000633b9aca004202946001600160401b03428704633b9aca0014421517159616915b818110613c7f57005b613c8a81838b6144b0565b90606082016001600160401b03613ca0826142dc565b1615159081613e8a575b5061327a578761326457608082016001600160401b03613cc9826142dc565b1615159081613e6d575b5061321d57613ce461308683614c5b565b806000526000602052878c888c6040600020541580613e54575b613d12575b50505050506001915001613c76565b6000936001600160a01b0393613d2e88613d6a9a9588956145ca565b96819688946040519c8d96879586937f087cca7f0000000000000000000000000000000000000000000000000000000085528b6004860161477f565b0393165af1918215610472578b600197600094613e13575b50613db984957f2ae6b88938c4134c3a165b9073ed03a3c043905f7b942f2eddb33745e14fecb0949550604051938493878561477f565b0390a18151613dce575b5050878c888c613d03565b613df9827fdc54d6fa75b81ef04ee8e27b86d4deabbc0dbc79d0b30f70349d335fc29cf76494614e13565b613e08604051928392836145a5565b0390a18b8080613dc3565b613e4c613db9917f2ae6b88938c4134c3a165b9073ed03a3c043905f7b942f2eddb33745e14fecb095963d8091833e6131f48183614023565b949350613d82565b856000526000602052600160f81b604060002055613cfe565b6001600160401b039150613e80906142dc565b168410158c613cd3565b6001600160401b039150613e9d906142dc565b164310158c613caa565b613ec0915060203d602011611592576115848183614023565b87613c43565b611eaa90613ed393614cab565b92613be9565b602060031982011261053757600435906001600160401b0382116105375760a09082900360031901126105375760040190565b6004359063ffffffff8216820361053757565b359063ffffffff8216820361053757565b90600182811c92168015613f60575b6020831014613f4a57565b634e487b7160e01b600052602260045260246000fd5b91607f1691613f3f565b60009291815491613f7a83613f30565b8083529260018116908115613fd05750600114613f9657505050565b60009081526020812093945091925b838310613fb6575060209250010190565b600181602092949394548385870101520191019190613fa5565b915050602093945060ff929192191683830152151560051b010190565b60a081019081106001600160401b038211176104f757604052565b608081019081106001600160401b038211176104f757604052565b90601f801991011681019081106001600160401b038211176104f757604052565b9060058210156110ad5752565b60005b8381106140645750506000910152565b8181015183820152602001614054565b9060209161408d81518092818552858086019101614051565b601f01601f1916010190565b9181601f84011215610537578235916001600160401b038311610537576020838186019501011161053757565b602060031982011261053757600435906001600160401b0382116105375760c09082900360031901126105375760040190565b602060031982011261053757600435906001600160401b0382116105375760809082900360031901126105375760040190565b600435906001600160a01b038216820361053757565b6001600160401b0381116104f757601f01601f191660200190565b92919261416982614142565b916141776040519384614023565b829481845281830111610537578281602093846000960137010152565b9080601f83011215610537578160206141af9335910161415d565b90565b602060031982011261053757600435906001600160401b0382116105375760409082900360031901126105375760040190565b9060048210156110ad5752565b602060031982011261053757600435906001600160401b0382116105375760609082900360031901126105375760040190565b35906001600160401b038216820361053757565b6020815263ffffffff825116602082015263ffffffff602083015116604082015260a06001600160401b03608061427e604086015184606087015260c0860190614074565b94826060820151168286015201511691015290565b903590601e198136030182121561053757018035906001600160401b03821161053757602001918160051b3603831361053757565b356001600160a01b03811681036105375790565b356001600160401b03811681036105375790565b903590601e198136030182121561053757018035906001600160401b0382116105375760200191813603831361053757565b908060209392818452848401376000828201840152601f01601f1916010190565b903590609e1981360301821215610537570190565b60043563ffffffff811681036105375790565b60243563ffffffff811681036105375790565b3563ffffffff811681036105375790565b601f821161439c57505050565b6000526020600020906020601f840160051c830193106143d7575b601f0160051c01905b8181106143cb575050565b600081556001016143c0565b90915081906143b7565b939260609363ffffffff6001600160a01b039481614416959a999a168852166020870152608060408701526080860191614322565b9416910152565b9395949061445260809463ffffffff80956001600160a01b03829516895216602088015260a0604088015260a0870190613f6a565b9616606085015216910152565b60409063ffffffff6141af95931681528160208201520191614322565b926144169063ffffffff6060946001600160a01b038295999899168752166020860152608060408601526080850190613f6a565b90821015611599576141af9160051b810190614343565b51906001600160401b038216820361053757565b9035601e19823603018112156105375701602081359101916001600160401b03821161053757813603831361053757565b9063ffffffff61451b83613f1f565b16815263ffffffff61452f60208401613f1f565b16602082015260806001600160401b0361457e8261456461455360408801886144db565b60a0604089015260a0880191614322565b958361457260608301614225565b16606087015201614225565b1691015290565b906001600160a01b0361441660209295949560408552604085019061450c565b90916145bc6141af9360408452604084019061450c565b916020818403910152614074565b90821015611599576145e19160051b8101906142f0565b9091565b926040926144169161460a6001600160a01b039498979860608852606088019061450c565b918683036020880152614322565b908160609103126105375760405190606082018281106001600160401b038211176104f75761465a9160409182528051845260208101516020850152016144c7565b604082015290565b6001600160a01b031680156146f2576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b602081830312610537578051906001600160401b038211610537570181601f8201121561053757805161475381614142565b926147616040519485614023565b81845260208284010111610537576141af9160208085019101614051565b6001600160a01b0361479f6141af9694959360608452606084019061450c565b941660208201526040818503910152614322565b63ffffffff16600052600460205260406000205460ff811660048110156110ad576003036110835760081c63ffffffff1690565b90816020910312610537575180151581036105375790565b9491926141af96946001600160401b036148449563ffffffff6148369516895216602088015260a0604088015260a0870191614322565b908482036060860152614074565b916080818403910152614074565b6000906148af60209694959761489861487c6001600160a01b0361487586614baa565b1697614ffa565b91604051928a840152898352614893604084614023565b615020565b90604051918983015288825261140f604083614023565b03925af1908115610472576000916148c5575090565b6141af915060203d602011611592576115848183614023565b63ffffffff60019116019063ffffffff821161326457565b7fc031b20c2b3a8a1fbfa9cc022aa3477489d4b8c91f0e667e900f5ad44daf8b6d600052600060205263ffffffff6040600020541663ffffffff614939826148de565b7fc031b20c2b3a8a1fbfa9cc022aa3477489d4b8c91f0e667e900f5ad44daf8b6d6000908152602052167fa948e29ac0e6a6a5e3c647a07a0505170c972dd4960cbe194aee77626bb52b585590565b906040519061499682613fed565b80549160ff831660058110156110ad576149f8614a029363ffffffff614a08966002948652818160081c16602087015260281c1660408501526040516149e381611c6e8160018601613f6a565b6060850152611c6e6040518094819301613f6a565b6080820152615020565b91614ffa565b6000526000602052604060002055565b7f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a600052600060205263ffffffff6040600020541663ffffffff614a5b826148de565b7f8ef07afda4dec4dc66e7d18fc0e3a713f74a11b33a71422c06a4b5e623c3b21a6000908152602052167f24072874bb11662934f0c68ca2659a14efae71555bb48eba2450fe6433183f955590565b6020949293956148af63ffffffff6000935460081c1691614adc6001600160a01b03614ad585614baa565b169661508f565b906040519189830152888252614af3604083614023565b60405163ffffffff60608b830193614b0c8582516141e5565b828d8201511660408501528260408201511682850152015116608082015260808152614b3960a082614023565b51902090604051918983015288825261140f604083614023565b90614a089060405163ffffffff602082019254614b738460ff83166141e5565b818160081c166040840152818160281c16606084015260481c16608082015260808152614ba160a082614023565b5190209161508f565b63ffffffff1660005260036020526001600160a01b03604060002054168015614bd05790565b7fb6c71f7d0000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303614c2d57565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b604051614c788161068c602082019460208652604083019061450c565b51902090565b906040519063ffffffff602083019360048552166040830152606082015260608152614c78608082614023565b60405190816020810193806040830160208752526060820160608260051b8401019184600090609e1981360301935b838310614cf9575050505050614c78925003601f198101835282614023565b919395509193605f19888203018252863586811215610537576020614d236001938683940161450c565b98019201930190959391879593614cda565b63ffffffff166000526005602052604060002060ff81541660058110156110ad57600303611d995790565b906040519063ffffffff602083019360058552166040830152606082015260608152614c78608082614023565b63ffffffff1660005260066020526001600160a01b03604060002054168015614db35790565b7fc6830cff0000000000000000000000000000000000000000000000000000000060005260046000fd5b611eaa614de992614c5b565b806000526000602052600160f81b60406000205403611f0557600052600060205260006040812055565b908160005260006020526040600020548015614eaf57600160f81b03614e85576001600160f81b0390604051614e6a60208281614e598183019687815193849201614051565b81010301601f198101835282614023565b51902016600160f81b17906000526000602052604060002055565b7f5c6d77110000000000000000000000000000000000000000000000000000000060005260046000fd5b7f53a55dcb0000000000000000000000000000000000000000000000000000000060005260046000fd5b9190604051602081019180604083016020855252606082019060608160051b8401019580926000915b838310614f37575050505050614f2a816001600160f81b03949503601f198101835282614023565b51902016600160f81b1790565b9091929397602080614f5e600193605f198a8203018752614f588d876144db565b90614322565b9a019301930191939290614f02565b6001600160f81b0391614f2a602060405183819483830196873781016000838201520301601f198101835282614023565b60405163ffffffff60208201926000845216604082015260408152614c78606082614023565b906001600160401b036040519163ffffffff60208401946001865216604084015216606082015260608152614c78608082614023565b60405163ffffffff60208201926003845216604082015260408152614c78606082614023565b604051614c788161068c602082019460208652615041604084018251614044565b63ffffffff602082015116606084015263ffffffff6040820151166080840152608061507b606083015160a08087015260e0860190614074565b910151838203603f190160c0850152614074565b60405163ffffffff60208201926002845216604082015260408152614c78606082614023565b60ff60008051602061518d8339815191525460401c16156150d257565b7fd7e6bcf80000000000000000000000000000000000000000000000000000000060005260046000fd5b9061513b575080511561511157805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b81511580615183575b61514c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b1561514456fef0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220587a41eff529d00dbece673951e108a71f34d6c6042ef0b5f8bded43eb79891e64736f6c634300081b0033
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.