From efc9bc3923541f993f7c00a6d4ed718dc166d654 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sat, 27 Jul 2024 10:14:23 +0900 Subject: [PATCH 1/3] feat: implemented ack packet --- src/ICS26Router.sol | 32 +++++++++++++++++++++++++++++-- src/errors/IICS26RouterErrors.sol | 2 ++ src/interfaces/IICS26Router.sol | 4 +++- src/utils/IBCStore.sol | 8 +++++--- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/ICS26Router.sol b/src/ICS26Router.sol index 379b9c7f..3d0e9cff 100644 --- a/src/ICS26Router.sol +++ b/src/ICS26Router.sol @@ -129,8 +129,36 @@ contract ICS26Router is IICS26Router, IBCStore, Ownable, IICS26RouterErrors, Ree /// @notice Acknowledges a packet /// @param msg_ The message for acknowledging packets function ackPacket(MsgAckPacket calldata msg_) external nonReentrant { - // TODO: implement - // IIBCApp app = IIBCApp(apps[msg.packet.sourcePort]); + IIBCApp app = IIBCApp(apps[msg_.packet.sourcePort]); + + string memory counterpartyId = ics02Client.getCounterparty(msg_.packet.sourceChannel).clientId; + if (keccak256(bytes(counterpartyId)) != keccak256(bytes(msg_.packet.destChannel))) { + revert IBCInvalidCounterparty(counterpartyId, msg_.packet.destChannel); + } + + // this will revert if the packet commitment does not exist + bytes32 storedCommitment = IBCStore.deletePacketCommitment(msg_.packet); + if (storedCommitment != ICS24Host.packetCommitmentBytes32(msg_.packet)) { + revert IBCPacketCommitmentMismatch(storedCommitment, ICS24Host.packetCommitmentBytes32(msg_.packet)); + } + + bytes memory commitmentPath = ICS24Host.packetAcknowledgementCommitmentPathCalldata( + msg_.packet.sourcePort, msg_.packet.sourceChannel, msg_.packet.sequence + ); + bytes32 commitmentBz = ICS24Host.packetAcknowledgementCommitmentBytes32(msg_.acknowledgement); + + // verify the packet acknowledgement + ILightClientMsgs.MsgMembership memory membershipMsg = ILightClientMsgs.MsgMembership({ + proof: msg_.proofAcked, + proofHeight: msg_.proofHeight, + kvPair: ILightClientMsgs.KVPair({path: commitmentPath, value: abi.encodePacked(commitmentBz)}) + }); + + ics02Client.getClient(msg_.packet.sourceChannel).verifyMembership(membershipMsg); + + app.onAcknowledgementPacket(IIBCAppCallbacks.OnAcknowledgementPacketCallback({packet: msg_.packet, acknowledgement: msg_.acknowledgement, relayer: msg.sender})); + + emit AckPacket(msg_.packet, msg_.acknowledgement); } /// @notice Timeouts a packet diff --git a/src/errors/IICS26RouterErrors.sol b/src/errors/IICS26RouterErrors.sol index 88815653..9cc92668 100644 --- a/src/errors/IICS26RouterErrors.sol +++ b/src/errors/IICS26RouterErrors.sol @@ -16,4 +16,6 @@ interface IICS26RouterErrors { error IBCInvalidCounterparty(string expected, string actual); error IBCAsyncAcknowledgementNotSupported(); + + error IBCPacketCommitmentMismatch(bytes32 expected, bytes32 actual); } diff --git a/src/interfaces/IICS26Router.sol b/src/interfaces/IICS26Router.sol index 0b067fe6..f42e69b2 100644 --- a/src/interfaces/IICS26Router.sol +++ b/src/interfaces/IICS26Router.sol @@ -42,8 +42,10 @@ interface IICS26Router is IICS26RouterMsgs { event SendPacket(Packet packet); /// @notice Emitted when a packet is received event RecvPacket(Packet packet); - /// @notice Emitted when a packet is acknowledged + /// @notice Emitted when a packet acknowledgement is written event WriteAcknowledgement(Packet packet, bytes acknowledgement); /// @notice Emitted when a packet is timed out event TimeoutPacket(Packet packet); + /// @notice Emitted when a packet is acknowledged + event AckPacket(Packet packet, bytes acknowledgement); } diff --git a/src/utils/IBCStore.sol b/src/utils/IBCStore.sol index f3540499..d0341262 100644 --- a/src/utils/IBCStore.sol +++ b/src/utils/IBCStore.sol @@ -49,17 +49,19 @@ abstract contract IBCStore is IIBCStore, IICS24HostErrors { commitments[path] = commitment; } - /// @notice Deletes a packet commitment + /// @notice Deletes a packet commitment and reverts if it does not exist /// @param packet The packet whose commitment to delete - function deletePacketCommitment(IICS26RouterMsgs.Packet memory packet) internal { + function deletePacketCommitment(IICS26RouterMsgs.Packet memory packet) internal returns (bytes32) { bytes32 path = ICS24Host.packetCommitmentKeyCalldata(packet.sourcePort, packet.sourceChannel, packet.sequence); - if (commitments[path] == 0) { + bytes32 commitment = commitments[path]; + if (commitment == 0) { revert IBCPacketCommitmentNotFound( ICS24Host.packetCommitmentPathCalldata(packet.sourcePort, packet.sourceChannel, packet.sequence) ); } delete commitments[path]; + return commitment; } /// @notice Sets a packet receipt From d0fb873c2178f18904ed9e9406b82fee551cc088 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sat, 27 Jul 2024 10:14:44 +0900 Subject: [PATCH 2/3] style: ran 'forge fmt' --- src/ICS26Router.sol | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ICS26Router.sol b/src/ICS26Router.sol index 3d0e9cff..1358766a 100644 --- a/src/ICS26Router.sol +++ b/src/ICS26Router.sol @@ -151,12 +151,18 @@ contract ICS26Router is IICS26Router, IBCStore, Ownable, IICS26RouterErrors, Ree ILightClientMsgs.MsgMembership memory membershipMsg = ILightClientMsgs.MsgMembership({ proof: msg_.proofAcked, proofHeight: msg_.proofHeight, - kvPair: ILightClientMsgs.KVPair({path: commitmentPath, value: abi.encodePacked(commitmentBz)}) + kvPair: ILightClientMsgs.KVPair({ path: commitmentPath, value: abi.encodePacked(commitmentBz) }) }); ics02Client.getClient(msg_.packet.sourceChannel).verifyMembership(membershipMsg); - app.onAcknowledgementPacket(IIBCAppCallbacks.OnAcknowledgementPacketCallback({packet: msg_.packet, acknowledgement: msg_.acknowledgement, relayer: msg.sender})); + app.onAcknowledgementPacket( + IIBCAppCallbacks.OnAcknowledgementPacketCallback({ + packet: msg_.packet, + acknowledgement: msg_.acknowledgement, + relayer: msg.sender + }) + ); emit AckPacket(msg_.packet, msg_.acknowledgement); } From d708342190f1f57bcb5138d5d230a446e948bf7f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sat, 27 Jul 2024 10:20:55 +0900 Subject: [PATCH 3/3] style: lint --- src/utils/IBCIdentifiers.sol | 3 --- test/IbcIdentifiers.t.sol | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/utils/IBCIdentifiers.sol b/src/utils/IBCIdentifiers.sol index 53be9885..0d0ffad1 100644 --- a/src/utils/IBCIdentifiers.sol +++ b/src/utils/IBCIdentifiers.sol @@ -1,9 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.25; -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { IICS26RouterMsgs } from "../msgs/IICS26RouterMsgs.sol"; - /// @title IBC Identifiers /// @notice Utilities for validating IBC identifiers library IBCIdentifiers { diff --git a/test/IbcIdentifiers.t.sol b/test/IbcIdentifiers.t.sol index cce3637d..bae03a7b 100644 --- a/test/IbcIdentifiers.t.sol +++ b/test/IbcIdentifiers.t.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.25 <0.9.0; +// solhint-disable custom-errors,max-line-length + import { Test } from "forge-std/src/Test.sol"; import { IBCIdentifiers } from "../src/utils/IBCIdentifiers.sol";