//SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import '@open-ibc/vibc-core-smart-contracts/contracts/libs/Ibc.sol'; import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcReceiver.sol'; import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcDispatcher.sol'; import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcMiddleware.sol'; // UniversalChanIbcApp is a contract that can be used as a base contract // for IBC-enabled contracts that send packets over the universal channel. contract UniversalChanIbcApp is IbcMwUser, IbcUniversalPacketReceiver { struct UcPacketWithChannel { bytes32 channelId; UniversalPacket packet; } struct UcAckWithChannel { bytes32 channelId; UniversalPacket packet; AckPacket ack; } // received packet as chain B UcPacketWithChannel[] public recvedPackets; // received ack packet as chain A UcAckWithChannel[] public ackPackets; // received timeout packet as chain A UcPacketWithChannel[] public timeoutPackets; constructor(address _middleware) IbcMwUser(_middleware) {} /** * @dev Implement a function to send a packet that calls the IbcUniversalPacketSender(mw).sendUniversalPacket function * It has the following function handle: * function sendUniversalPacket( bytes32 channelId, bytes32 destPortAddr, bytes calldata appData, uint64 timeoutTimestamp ) external; */ /** * @dev Packet lifecycle callback that implements packet receipt logic and returns and acknowledgement packet. * MUST be overriden by the inheriting contract. * * @param channelId the ID of the channel (locally) the packet was received on. * @param packet the Universal packet encoded by the source and relayed by the relayer. */ function onRecvUniversalPacket( bytes32 channelId, UniversalPacket calldata packet ) external virtual onlyIbcMw returns (AckPacket memory ackPacket) { recvedPackets.push(UcPacketWithChannel(channelId, packet)); // 1. decode the packet.data // 2. do logic // 3. encode the ack packet (encoding format should be agreed between the two applications) // below is an example, the actual ackpacket data should be implemented by the contract developer return AckPacket(true, abi.encodePacked(address(this), IbcUtils.toAddress(packet.srcPortAddr), 'ack-', packet.appData)); } /** * @dev Packet lifecycle callback that implements packet acknowledgment logic. * MUST be overriden by the inheriting contract. * * @param channelId the ID of the channel (locally) the ack was received on. * @param packet the Universal packet encoded by the source and relayed by the relayer. * @param ack the acknowledgment packet encoded by the destination and relayed by the relayer. */ function onUniversalAcknowledgement( bytes32 channelId, UniversalPacket memory packet, AckPacket calldata ack ) external virtual onlyIbcMw { ackPackets.push(UcAckWithChannel(channelId, packet, ack)); // 1. decode the ack.data // 2. do logic } /** * @dev Packet lifecycle callback that implements packet receipt logic and return and acknowledgement packet. * MUST be overriden by the inheriting contract. * NOT SUPPORTED YET * * @param channelId the ID of the channel (locally) the timeout was submitted on. * @param packet the Universal packet encoded by the counterparty and relayed by the relayer */ function onTimeoutUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) external virtual onlyIbcMw { timeoutPackets.push(UcPacketWithChannel(channelId, packet)); // do logic } }