From 3e831aad68c5b6723cd19a24edceccad6ea42718 Mon Sep 17 00:00:00 2001 From: wenwei Date: Fri, 1 Mar 2024 13:29:55 +0100 Subject: [PATCH 1/9] forge install: vibc-core-smart-contracts 15b77e898b2a368c735fc61c7323f10091907858 --- .gitmodules | 3 +++ lib/vibc-core-smart-contracts | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/vibc-core-smart-contracts diff --git a/.gitmodules b/.gitmodules index 690924b..cf378b7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "lib/openzeppelin-contracts"] path = lib/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts +[submodule "lib/vibc-core-smart-contracts"] + path = lib/vibc-core-smart-contracts + url = https://github.com/open-ibc/vibc-core-smart-contracts diff --git a/lib/vibc-core-smart-contracts b/lib/vibc-core-smart-contracts new file mode 160000 index 0000000..15b77e8 --- /dev/null +++ b/lib/vibc-core-smart-contracts @@ -0,0 +1 @@ +Subproject commit 15b77e898b2a368c735fc61c7323f10091907858 From 91fc145539ac6a0abcc30fa556d5283e3998e730 Mon Sep 17 00:00:00 2001 From: wenwei Date: Fri, 1 Mar 2024 13:29:55 +0100 Subject: [PATCH 2/9] install polymer vibc SCs dep; initialize IncentivizedPolymerEscrow --- remappings.txt | 3 +- .../polymer/IncentivizedPolymerEscrow.sol | 162 ++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/apps/polymer/IncentivizedPolymerEscrow.sol diff --git a/remappings.txt b/remappings.txt index 8ced12a..104eeca 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,2 +1,3 @@ forge-std/=lib/forge-std/src/ -openzeppelin/=lib/openzeppelin-contracts/contracts/ \ No newline at end of file +openzeppelin/=lib/openzeppelin-contracts/contracts/ +vibc-core-smart-contracts/=lib/vibc-core-smart-contracts/contracts/ \ No newline at end of file diff --git a/src/apps/polymer/IncentivizedPolymerEscrow.sol b/src/apps/polymer/IncentivizedPolymerEscrow.sol new file mode 100644 index 0000000..27919b2 --- /dev/null +++ b/src/apps/polymer/IncentivizedPolymerEscrow.sol @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {IMETimeoutExtension} from "../../TimeoutExtension.sol"; +import {MockOnRecvAMB} from "../../../test/mocks/MockOnRecvAMB.sol"; + +import {AckPacket} from "vibc-core-smart-contracts/Ibc.sol"; +import { + IbcMwUser, + UniversalPacket, + IbcUniversalPacketSender, + IbcUniversalPacketReceiver +} from "vibc-core-smart-contracts/IbcMiddleware.sol"; + +// This is an example contract which exposes an onReceive interface. This is for messaging protocols +// where messages are delivered directly to the messaging protocol's contract rather than this contract. +// Comments marked by * imply that an integration point should be changed by external contracts. +contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser { + error NotEnoughGasProvidedForVerification(); + error NonVerifiableMessage(); + error NotImplemented(); + + // Internal function for gas savings. + function _UNIQUE_SOURCE_IDENTIFIER() internal view returns (bytes32) { + return bytes32(block.chainid); + } + + // Expose internal function. + function UNIQUE_SOURCE_IDENTIFIER() external view returns (bytes32) { + return _UNIQUE_SOURCE_IDENTIFIER(); + } + + struct VerifiedMessageHashContext { + bytes32 chainIdentifier; + bytes implementationIdentifier; + } + + mapping(bytes32 => VerifiedMessageHashContext) public isVerifiedMessageHash; + + constructor(address sendLostGasTo, address messagingProtocol) + IMETimeoutExtension(sendLostGasTo) + IbcMwUser(messagingProtocol) + {} + + function estimateAdditionalCost() external pure returns (address asset, uint256 amount) { + asset = address(0); + amount = 0; + } + + function _getMessageIdentifier(bytes32 destinationIdentifier, bytes calldata message) + internal + view + override + returns (bytes32) + { + return keccak256( + abi.encodePacked(bytes32(block.number), _UNIQUE_SOURCE_IDENTIFIER(), destinationIdentifier, message) + ); + } + + function _verifyPacket(bytes calldata, /* _metadata */ bytes calldata _message) + internal + view + override + returns (bytes32 sourceIdentifier, bytes memory implementationIdentifier, bytes calldata message_) + { + sourceIdentifier = isVerifiedMessageHash[keccak256(_message)].chainIdentifier; + implementationIdentifier = isVerifiedMessageHash[keccak256(_message)].implementationIdentifier; + + if (sourceIdentifier == bytes32(0)) revert NonVerifiableMessage(); + + message_ = _message; + } + + /// @dev This is an example of how this function can be disabled. + /// This doesn't have to be how it is done. This implementation works + /// fine with and without (There is even a test for that). + function processPacket( + bytes calldata, /* messagingProtocolContext */ + bytes calldata, /* rawMessage */ + bytes32 /* feeRecipitent */ + ) external payable override { + revert NotImplemented(); + } + + // packet.srcPortAddr is the IncentivizedPolymerEscrow address on the source chain. + // packet.destPortAddr is the address of this contract. + // channelId: the universal channel id on the source chain, which can be used to identify the source chain. + function onRecvUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) + external + onlyIbcMw + returns (AckPacket memory) + { + uint256 gasLimit = gasleft(); + bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); + + bytes memory sourceImplementationIdentifier = abi.encodePacked(packet.srcPortAddr); + + bytes memory receiveAck = _handleMessage( + bytes32(abi.encodePacked(packet.srcPortAddr)), + sourceImplementationIdentifier, + packet.appData, + feeRecipitent, + gasLimit + ); + + // Send ack: + return AckPacket({success: true, data: receiveAck}); + } + + // The escrow manages acks, so any message can be directly provided to _onReceive. + function onUniversalAcknowledgement(UniversalPacket calldata packet, AckPacket calldata ack) external onlyIbcMw { + uint256 gasLimit = gasleft(); + bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); + + bytes calldata rawMessage = ack.data; + // TODO: get dest chain ID? + bytes32 chainIdentifier; + bytes memory destinationImplementationIdentifier = abi.encodePacked(packet.destPortAddr); + + isVerifiedMessageHash[keccak256(rawMessage)] = VerifiedMessageHashContext({ + chainIdentifier: chainIdentifier, + implementationIdentifier: destinationImplementationIdentifier + }); + _handleAck(chainIdentifier, destinationImplementationIdentifier, rawMessage, feeRecipitent, gasLimit); + } + + // For timeouts, we need to construct the message. + function onTimeoutUniversalPacket(UniversalPacket calldata packet) external onlyIbcMw { + uint256 gasLimit = gasleft(); + bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); + + bytes calldata rawMessage = packet.appData; + // TODO: get dest chain ID? + bytes32 chainIdentifier; + + _handleTimeout(chainIdentifier, rawMessage, feeRecipitent, gasLimit); + } + + // * Send to messaging_protocol + function _sendPacket( + bytes32 destinationChainIdentifier, + bytes memory, /* destinationImplementation */ + bytes memory message + ) internal override returns (uint128 costOfsendPacketInNativeToken) { + // TODO: get Polymer universal channelId from Polymer registry. Each channelID is unique for a pair of chains. + bytes32 channelId = _getChannelId(destinationChainIdentifier); + // TODO: get IncentivizedPolymerEscrow address deployed on the destination chain. + address destEscrowAddr; + // set timeoutTimestamp to 1 day from now. It's the dest chain's block time in nanoseconds since the epoch. + uint64 timeoutTimestamp = uint64(block.timestamp + 1 days) * 1e9; + IbcUniversalPacketSender(mw).sendUniversalPacket(channelId, destEscrowAddr, message, timeoutTimestamp); + return 0; + } + + mapping(bytes32 => bytes32) _destChainChannelIds; + + function _getChannelId(bytes32 destChainId) internal view returns (bytes32) { + // verify destChainId has a valid channelId + return _destChainChannelIds[destChainId]; + } +} From 29eb419fe9a530e8330eaaeede94ed07e2ade13d Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 1 Mar 2024 13:29:55 +0100 Subject: [PATCH 3/9] chore: documentation updates --- src/apps/polymer/IncentivizedPolymerEscrow.sol | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/apps/polymer/IncentivizedPolymerEscrow.sol b/src/apps/polymer/IncentivizedPolymerEscrow.sol index 27919b2..b465b98 100644 --- a/src/apps/polymer/IncentivizedPolymerEscrow.sol +++ b/src/apps/polymer/IncentivizedPolymerEscrow.sol @@ -12,9 +12,7 @@ import { IbcUniversalPacketReceiver } from "vibc-core-smart-contracts/IbcMiddleware.sol"; -// This is an example contract which exposes an onReceive interface. This is for messaging protocols -// where messages are delivered directly to the messaging protocol's contract rather than this contract. -// Comments marked by * imply that an integration point should be changed by external contracts. +/// @notice Polymer implementation of the Generalised Incentives based on vIBC. contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser { error NotEnoughGasProvidedForVerification(); error NonVerifiableMessage(); @@ -58,6 +56,8 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser { ); } + /// @notice This function is used to allow acks to be executed twice (if the first one ran out of gas) + /// This is not intended to allow processPacket to work. function _verifyPacket(bytes calldata, /* _metadata */ bytes calldata _message) internal view @@ -72,9 +72,7 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser { message_ = _message; } - /// @dev This is an example of how this function can be disabled. - /// This doesn't have to be how it is done. This implementation works - /// fine with and without (There is even a test for that). + /// @dev Disable processPacket function processPacket( bytes calldata, /* messagingProtocolContext */ bytes calldata, /* rawMessage */ @@ -108,7 +106,7 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser { return AckPacket({success: true, data: receiveAck}); } - // The escrow manages acks, so any message can be directly provided to _onReceive. + // The escrow manages acks, so any message can be directly provided to _handleAck. function onUniversalAcknowledgement(UniversalPacket calldata packet, AckPacket calldata ack) external onlyIbcMw { uint256 gasLimit = gasleft(); bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); From 331227d9982aa3f3e8495d17d1c93059f2931302 Mon Sep 17 00:00:00 2001 From: wenwei Date: Fri, 1 Mar 2024 13:29:56 +0100 Subject: [PATCH 4/9] update vibc-core-smart-contracts ref with bytes32 addresses Also - Enforce IncentivizedPolymerEscrow implementation of IbcUniversalPacketReceiver interface --- lib/vibc-core-smart-contracts | 2 +- src/apps/polymer/IncentivizedPolymerEscrow.sol | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/vibc-core-smart-contracts b/lib/vibc-core-smart-contracts index 15b77e8..f9ca658 160000 --- a/lib/vibc-core-smart-contracts +++ b/lib/vibc-core-smart-contracts @@ -1 +1 @@ -Subproject commit 15b77e898b2a368c735fc61c7323f10091907858 +Subproject commit f9ca65866e4240eb51ce46dfa69cd2895301a300 diff --git a/src/apps/polymer/IncentivizedPolymerEscrow.sol b/src/apps/polymer/IncentivizedPolymerEscrow.sol index b465b98..6455f72 100644 --- a/src/apps/polymer/IncentivizedPolymerEscrow.sol +++ b/src/apps/polymer/IncentivizedPolymerEscrow.sol @@ -13,7 +13,7 @@ import { } from "vibc-core-smart-contracts/IbcMiddleware.sol"; /// @notice Polymer implementation of the Generalised Incentives based on vIBC. -contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser { +contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUniversalPacketReceiver { error NotEnoughGasProvidedForVerification(); error NonVerifiableMessage(); error NotImplemented(); @@ -107,7 +107,10 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser { } // The escrow manages acks, so any message can be directly provided to _handleAck. - function onUniversalAcknowledgement(UniversalPacket calldata packet, AckPacket calldata ack) external onlyIbcMw { + function onUniversalAcknowledgement(bytes32 channelId, UniversalPacket calldata packet, AckPacket calldata ack) + external + onlyIbcMw + { uint256 gasLimit = gasleft(); bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); @@ -124,7 +127,7 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser { } // For timeouts, we need to construct the message. - function onTimeoutUniversalPacket(UniversalPacket calldata packet) external onlyIbcMw { + function onTimeoutUniversalPacket(bytes32 chanelId, UniversalPacket calldata packet) external onlyIbcMw { uint256 gasLimit = gasleft(); bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); @@ -143,11 +146,11 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser { ) internal override returns (uint128 costOfsendPacketInNativeToken) { // TODO: get Polymer universal channelId from Polymer registry. Each channelID is unique for a pair of chains. bytes32 channelId = _getChannelId(destinationChainIdentifier); - // TODO: get IncentivizedPolymerEscrow address deployed on the destination chain. - address destEscrowAddr; // set timeoutTimestamp to 1 day from now. It's the dest chain's block time in nanoseconds since the epoch. uint64 timeoutTimestamp = uint64(block.timestamp + 1 days) * 1e9; - IbcUniversalPacketSender(mw).sendUniversalPacket(channelId, destEscrowAddr, message, timeoutTimestamp); + IbcUniversalPacketSender(mw).sendUniversalPacket( + channelId, destinationChainIdentifier, message, timeoutTimestamp + ); return 0; } From 8032d272d083b484fad3aab6e9d1c197323ea920 Mon Sep 17 00:00:00 2001 From: wenwei Date: Fri, 1 Mar 2024 13:29:56 +0100 Subject: [PATCH 5/9] add bidirectional lookups between destination chain ID and channel ID --- .../polymer/IncentivizedPolymerEscrow.sol | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/apps/polymer/IncentivizedPolymerEscrow.sol b/src/apps/polymer/IncentivizedPolymerEscrow.sol index 6455f72..0cf7c76 100644 --- a/src/apps/polymer/IncentivizedPolymerEscrow.sol +++ b/src/apps/polymer/IncentivizedPolymerEscrow.sol @@ -115,8 +115,7 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); bytes calldata rawMessage = ack.data; - // TODO: get dest chain ID? - bytes32 chainIdentifier; + bytes32 chainIdentifier = _getChannelId(channelId); bytes memory destinationImplementationIdentifier = abi.encodePacked(packet.destPortAddr); isVerifiedMessageHash[keccak256(rawMessage)] = VerifiedMessageHashContext({ @@ -127,15 +126,12 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers } // For timeouts, we need to construct the message. - function onTimeoutUniversalPacket(bytes32 chanelId, UniversalPacket calldata packet) external onlyIbcMw { + function onTimeoutUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) external onlyIbcMw { uint256 gasLimit = gasleft(); bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); bytes calldata rawMessage = packet.appData; - // TODO: get dest chain ID? - bytes32 chainIdentifier; - - _handleTimeout(chainIdentifier, rawMessage, feeRecipitent, gasLimit); + _handleTimeout(_getDestChainId(channelId), rawMessage, feeRecipitent, gasLimit); } // * Send to messaging_protocol @@ -144,7 +140,7 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers bytes memory, /* destinationImplementation */ bytes memory message ) internal override returns (uint128 costOfsendPacketInNativeToken) { - // TODO: get Polymer universal channelId from Polymer registry. Each channelID is unique for a pair of chains. + // call `setChannelId` to set the channelId for the destination chain before calling this function. bytes32 channelId = _getChannelId(destinationChainIdentifier); // set timeoutTimestamp to 1 day from now. It's the dest chain's block time in nanoseconds since the epoch. uint64 timeoutTimestamp = uint64(block.timestamp + 1 days) * 1e9; @@ -154,10 +150,26 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers return 0; } + // ChannelIds are always from the running chain's perspective. + // Each universal channel/channelId represents a directional path from the running chain to a destination chain. + // Universal ChannelIds should _destChainIdToChannelIdd from the Polymer registry. + // Although everyone is free to establish their own channels, they're not "officially" vetted until they're in the Polymer registry. mapping(bytes32 => bytes32) _destChainChannelIds; + mapping(bytes32 => bytes32) _channelIdToDestChainId; + + // Contract owner set a map of allowed channelIds for each destination chain. + function setChannelId(bytes32 destChainId, bytes32 channelId) external onlyOwner { + _destChainChannelIds[destChainId] = channelId; + _channelIdToDestChainId[channelId] = destChainId; + } function _getChannelId(bytes32 destChainId) internal view returns (bytes32) { // verify destChainId has a valid channelId return _destChainChannelIds[destChainId]; } + + function _getDestChainId(bytes32 channelId) internal view returns (bytes32) { + // verify channelId has a valid destChainId + return _channelIdToDestChainId[channelId]; + } } From 85eac7f00423935c7f5b0eac0ab3d7b39012c4bd Mon Sep 17 00:00:00 2001 From: wenwei Date: Fri, 1 Mar 2024 13:29:56 +0100 Subject: [PATCH 6/9] address PR comments --- .../polymer/IncentivizedPolymerEscrow.sol | 61 ++++++------------- 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/src/apps/polymer/IncentivizedPolymerEscrow.sol b/src/apps/polymer/IncentivizedPolymerEscrow.sol index 0cf7c76..136aa72 100644 --- a/src/apps/polymer/IncentivizedPolymerEscrow.sol +++ b/src/apps/polymer/IncentivizedPolymerEscrow.sol @@ -34,6 +34,8 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers } mapping(bytes32 => VerifiedMessageHashContext) public isVerifiedMessageHash; + // packet will timeout if it's delivered on the destination chain after (this block time + _TIMEOUT_AFTER_BLOCK). + uint64 constant _TIMEOUT_AFTER_BLOCK = 1 days; constructor(address sendLostGasTo, address messagingProtocol) IMETimeoutExtension(sendLostGasTo) @@ -83,7 +85,7 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers // packet.srcPortAddr is the IncentivizedPolymerEscrow address on the source chain. // packet.destPortAddr is the address of this contract. - // channelId: the universal channel id on the source chain, which can be used to identify the source chain. + // channelId: the universal channel id from the running chain's perspective, which can be used to identify the counterparty chain. function onRecvUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) external onlyIbcMw @@ -94,13 +96,8 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers bytes memory sourceImplementationIdentifier = abi.encodePacked(packet.srcPortAddr); - bytes memory receiveAck = _handleMessage( - bytes32(abi.encodePacked(packet.srcPortAddr)), - sourceImplementationIdentifier, - packet.appData, - feeRecipitent, - gasLimit - ); + bytes memory receiveAck = + _handleMessage(channelId, sourceImplementationIdentifier, packet.appData, feeRecipitent, gasLimit); // Send ack: return AckPacket({success: true, data: receiveAck}); @@ -115,14 +112,13 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); bytes calldata rawMessage = ack.data; - bytes32 chainIdentifier = _getChannelId(channelId); bytes memory destinationImplementationIdentifier = abi.encodePacked(packet.destPortAddr); isVerifiedMessageHash[keccak256(rawMessage)] = VerifiedMessageHashContext({ - chainIdentifier: chainIdentifier, + chainIdentifier: channelId, implementationIdentifier: destinationImplementationIdentifier }); - _handleAck(chainIdentifier, destinationImplementationIdentifier, rawMessage, feeRecipitent, gasLimit); + _handleAck(channelId, destinationImplementationIdentifier, rawMessage, feeRecipitent, gasLimit); } // For timeouts, we need to construct the message. @@ -131,45 +127,28 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); bytes calldata rawMessage = packet.appData; - _handleTimeout(_getDestChainId(channelId), rawMessage, feeRecipitent, gasLimit); + _handleTimeout(channelId, rawMessage, feeRecipitent, gasLimit); } // * Send to messaging_protocol + /** + * @param destinationChainIdentifier Universal Channel ID. It's always from the running chain's perspective. + * Each universal channel/channelId represents a directional path from the running chain to a destination chain. + * Universal ChannelIds should _destChainIdToChannelIdd from the Polymer registry. + * Although everyone is free to establish their own channels, they're not "officially" vetted until they're in the Polymer registry. + * @param destinationImplementation IncentivizedPolymerEscrow address on the counterparty chain. + * @param message packet payload + */ function _sendPacket( bytes32 destinationChainIdentifier, - bytes memory, /* destinationImplementation */ + bytes memory destinationImplementation, bytes memory message ) internal override returns (uint128 costOfsendPacketInNativeToken) { - // call `setChannelId` to set the channelId for the destination chain before calling this function. - bytes32 channelId = _getChannelId(destinationChainIdentifier); - // set timeoutTimestamp to 1 day from now. It's the dest chain's block time in nanoseconds since the epoch. - uint64 timeoutTimestamp = uint64(block.timestamp + 1 days) * 1e9; + // Packet will timeout after the dest chain's block time in nanoseconds since the epoch passes timeoutTimestamp. + uint64 timeoutTimestamp = uint64(block.timestamp + _TIMEOUT_AFTER_BLOCK) * 1e9; IbcUniversalPacketSender(mw).sendUniversalPacket( - channelId, destinationChainIdentifier, message, timeoutTimestamp + destinationChainIdentifier, bytes32(destinationImplementation), message, timeoutTimestamp ); return 0; } - - // ChannelIds are always from the running chain's perspective. - // Each universal channel/channelId represents a directional path from the running chain to a destination chain. - // Universal ChannelIds should _destChainIdToChannelIdd from the Polymer registry. - // Although everyone is free to establish their own channels, they're not "officially" vetted until they're in the Polymer registry. - mapping(bytes32 => bytes32) _destChainChannelIds; - mapping(bytes32 => bytes32) _channelIdToDestChainId; - - // Contract owner set a map of allowed channelIds for each destination chain. - function setChannelId(bytes32 destChainId, bytes32 channelId) external onlyOwner { - _destChainChannelIds[destChainId] = channelId; - _channelIdToDestChainId[channelId] = destChainId; - } - - function _getChannelId(bytes32 destChainId) internal view returns (bytes32) { - // verify destChainId has a valid channelId - return _destChainChannelIds[destChainId]; - } - - function _getDestChainId(bytes32 channelId) internal view returns (bytes32) { - // verify channelId has a valid destChainId - return _channelIdToDestChainId[channelId]; - } } From 70068f1a64e2576702077fdabaa5a7198a48f4b1 Mon Sep 17 00:00:00 2001 From: wenwei Date: Fri, 1 Mar 2024 13:29:56 +0100 Subject: [PATCH 7/9] update vibc-smart-contracts to v1.0.0-07362dd18a7caed421a9ba5c4fcbca56c75373b8 --- lib/vibc-core-smart-contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vibc-core-smart-contracts b/lib/vibc-core-smart-contracts index f9ca658..07362dd 160000 --- a/lib/vibc-core-smart-contracts +++ b/lib/vibc-core-smart-contracts @@ -1 +1 @@ -Subproject commit f9ca65866e4240eb51ce46dfa69cd2895301a300 +Subproject commit 07362dd18a7caed421a9ba5c4fcbca56c75373b8 From 548168ec235691f23927fe16a7d4fc6d310e4e8b Mon Sep 17 00:00:00 2001 From: wenwei Date: Fri, 1 Mar 2024 13:29:56 +0100 Subject: [PATCH 8/9] conform to IncentivizedMessageEscrow --- .../polymer/IncentivizedPolymerEscrow.sol | 63 ++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/src/apps/polymer/IncentivizedPolymerEscrow.sol b/src/apps/polymer/IncentivizedPolymerEscrow.sol index 136aa72..a935693 100644 --- a/src/apps/polymer/IncentivizedPolymerEscrow.sol +++ b/src/apps/polymer/IncentivizedPolymerEscrow.sol @@ -1,33 +1,23 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; -import {IMETimeoutExtension} from "../../TimeoutExtension.sol"; -import {MockOnRecvAMB} from "../../../test/mocks/MockOnRecvAMB.sol"; +import {IncentivizedMessageEscrow} from "../../IncentivizedMessageEscrow.sol"; +import "../../MessagePayload.sol"; -import {AckPacket} from "vibc-core-smart-contracts/Ibc.sol"; +import {AckPacket} from "vibc-core-smart-contracts/libs/Ibc.sol"; import { IbcMwUser, UniversalPacket, IbcUniversalPacketSender, IbcUniversalPacketReceiver -} from "vibc-core-smart-contracts/IbcMiddleware.sol"; +} from "vibc-core-smart-contracts/interfaces/IbcMiddleware.sol"; /// @notice Polymer implementation of the Generalised Incentives based on vIBC. -contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUniversalPacketReceiver { +contract IncentivizedPolymerEscrow is IncentivizedMessageEscrow, IbcMwUser, IbcUniversalPacketReceiver { error NotEnoughGasProvidedForVerification(); error NonVerifiableMessage(); error NotImplemented(); - // Internal function for gas savings. - function _UNIQUE_SOURCE_IDENTIFIER() internal view returns (bytes32) { - return bytes32(block.chainid); - } - - // Expose internal function. - function UNIQUE_SOURCE_IDENTIFIER() external view returns (bytes32) { - return _UNIQUE_SOURCE_IDENTIFIER(); - } - struct VerifiedMessageHashContext { bytes32 chainIdentifier; bytes implementationIdentifier; @@ -38,7 +28,7 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers uint64 constant _TIMEOUT_AFTER_BLOCK = 1 days; constructor(address sendLostGasTo, address messagingProtocol) - IMETimeoutExtension(sendLostGasTo) + IncentivizedMessageEscrow(sendLostGasTo) IbcMwUser(messagingProtocol) {} @@ -47,20 +37,26 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers amount = 0; } - function _getMessageIdentifier(bytes32 destinationIdentifier, bytes calldata message) - internal - view - override - returns (bytes32) - { - return keccak256( - abi.encodePacked(bytes32(block.number), _UNIQUE_SOURCE_IDENTIFIER(), destinationIdentifier, message) - ); + function _uniqueSourceIdentifier() internal view override returns (bytes32 sourceIdentifier) { + return sourceIdentifier = bytes32(block.chainid); + } + + function _proofValidPeriod(bytes32 /* destinationIdentifier */ ) internal pure override returns (uint64) { + return 0; + } + + /// @dev Disable processPacket + function processPacket( + bytes calldata, /* messagingProtocolContext */ + bytes calldata, /* rawMessage */ + bytes32 /* feeRecipitent */ + ) external payable override { + revert NotImplemented(); } /// @notice This function is used to allow acks to be executed twice (if the first one ran out of gas) /// This is not intended to allow processPacket to work. - function _verifyPacket(bytes calldata, /* _metadata */ bytes calldata _message) + function _verifyPacket(bytes calldata, /* messagingProtocolContext */ bytes calldata _message) internal view override @@ -74,15 +70,6 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers message_ = _message; } - /// @dev Disable processPacket - function processPacket( - bytes calldata, /* messagingProtocolContext */ - bytes calldata, /* rawMessage */ - bytes32 /* feeRecipitent */ - ) external payable override { - revert NotImplemented(); - } - // packet.srcPortAddr is the IncentivizedPolymerEscrow address on the source chain. // packet.destPortAddr is the address of this contract. // channelId: the universal channel id from the running chain's perspective, which can be used to identify the counterparty chain. @@ -127,7 +114,11 @@ contract IncentivizedPolymerEscrow is IMETimeoutExtension, IbcMwUser, IbcUnivers bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); bytes calldata rawMessage = packet.appData; - _handleTimeout(channelId, rawMessage, feeRecipitent, gasLimit); + bytes32 messageIdentifier = bytes32(rawMessage[MESSAGE_IDENTIFIER_START:MESSAGE_IDENTIFIER_END]); + address fromApplication = address(uint160(bytes20(rawMessage[FROM_APPLICATION_START_EVM:FROM_APPLICATION_END]))); + _handleTimeout( + channelId, messageIdentifier, fromApplication, rawMessage[CTX0_MESSAGE_START:], feeRecipitent, gasLimit + ); } // * Send to messaging_protocol From 9cd7c6412db80747de48375a26086e4a123268ba Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 1 Mar 2024 13:29:56 +0100 Subject: [PATCH 9/9] feat: disable unused contracts and fetch update to _sendPacket to set timeoutTimestamp --- .../polymer/IncentivizedPolymerEscrow.sol | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/apps/polymer/IncentivizedPolymerEscrow.sol b/src/apps/polymer/IncentivizedPolymerEscrow.sol index a935693..0a9ab3a 100644 --- a/src/apps/polymer/IncentivizedPolymerEscrow.sol +++ b/src/apps/polymer/IncentivizedPolymerEscrow.sol @@ -45,7 +45,7 @@ contract IncentivizedPolymerEscrow is IncentivizedMessageEscrow, IbcMwUser, IbcU return 0; } - /// @dev Disable processPacket + /** @dev Disable processPacket */ function processPacket( bytes calldata, /* messagingProtocolContext */ bytes calldata, /* rawMessage */ @@ -54,6 +54,25 @@ contract IncentivizedPolymerEscrow is IncentivizedMessageEscrow, IbcMwUser, IbcU revert NotImplemented(); } + /** @dev Disable reemitAckMessage. Polymer manages the entire flow, so we don't need to worry about expired proofs. */ + function reemitAckMessage( + bytes32 /* sourceIdentifier */, + bytes calldata /* implementationIdentifier */, + bytes calldata /* receiveAckWithContext */ + ) external payable override { + revert NotImplemented(); + } + + /** @dev Disable timeoutMessage */ + function timeoutMessage( + bytes32 /* sourceIdentifier */, + bytes calldata /* implementationIdentifier */, + uint256 /* originBlockNumber */, + bytes calldata /* message */ + ) external payable override { + revert NotImplemented(); + } + /// @notice This function is used to allow acks to be executed twice (if the first one ran out of gas) /// This is not intended to allow processPacket to work. function _verifyPacket(bytes calldata, /* messagingProtocolContext */ bytes calldata _message) @@ -81,7 +100,7 @@ contract IncentivizedPolymerEscrow is IncentivizedMessageEscrow, IbcMwUser, IbcU uint256 gasLimit = gasleft(); bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); - bytes memory sourceImplementationIdentifier = abi.encodePacked(packet.srcPortAddr); + bytes memory sourceImplementationIdentifier = bytes.concat(packet.srcPortAddr); bytes memory receiveAck = _handleMessage(channelId, sourceImplementationIdentifier, packet.appData, feeRecipitent, gasLimit); @@ -99,7 +118,7 @@ contract IncentivizedPolymerEscrow is IncentivizedMessageEscrow, IbcMwUser, IbcU bytes32 feeRecipitent = bytes32(uint256(uint160(tx.origin))); bytes calldata rawMessage = ack.data; - bytes memory destinationImplementationIdentifier = abi.encodePacked(packet.destPortAddr); + bytes memory destinationImplementationIdentifier = bytes.concat(packet.destPortAddr); isVerifiedMessageHash[keccak256(rawMessage)] = VerifiedMessageHashContext({ chainIdentifier: channelId, @@ -121,7 +140,6 @@ contract IncentivizedPolymerEscrow is IncentivizedMessageEscrow, IbcMwUser, IbcU ); } - // * Send to messaging_protocol /** * @param destinationChainIdentifier Universal Channel ID. It's always from the running chain's perspective. * Each universal channel/channelId represents a directional path from the running chain to a destination chain. @@ -129,14 +147,17 @@ contract IncentivizedPolymerEscrow is IncentivizedMessageEscrow, IbcMwUser, IbcU * Although everyone is free to establish their own channels, they're not "officially" vetted until they're in the Polymer registry. * @param destinationImplementation IncentivizedPolymerEscrow address on the counterparty chain. * @param message packet payload + * @param deadline Packet will timeout after the dest chain's block time in nanoseconds since the epoch passes timeoutTimestamp. */ function _sendPacket( bytes32 destinationChainIdentifier, bytes memory destinationImplementation, - bytes memory message + bytes memory message, + uint64 deadline ) internal override returns (uint128 costOfsendPacketInNativeToken) { - // Packet will timeout after the dest chain's block time in nanoseconds since the epoch passes timeoutTimestamp. - uint64 timeoutTimestamp = uint64(block.timestamp + _TIMEOUT_AFTER_BLOCK) * 1e9; + // If timeoutTimestamp is set to 0, set it to maximum. This does not really apply to Polymer since it is an onRecv implementation + // but it should still conform to the general spec of Generalised Incentives. + uint64 timeoutTimestamp = deadline > 0 ? deadline : type(uint64).max; IbcUniversalPacketSender(mw).sendUniversalPacket( destinationChainIdentifier, bytes32(destinationImplementation), message, timeoutTimestamp );