Skip to content

Commit

Permalink
enforce channel incentivization status check in Dipatcher's two recv …
Browse files Browse the repository at this point in the history
…ack methods
  • Loading branch information
WenweiX authored and alfredo-stonk committed Aug 28, 2023
1 parent 54ce490 commit 78c3168
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 8 deletions.
11 changes: 11 additions & 0 deletions contracts/Dispatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ contract Dispatcher is IbcDispatcher, Ownable {
address indexed portAddress,
string version,
ChannelOrder ordering,
bool feeEnabled,
string[] connectionHops,
string counterpartyPortId,
bytes32 counterpartyChannelId
Expand Down Expand Up @@ -374,6 +375,7 @@ contract Dispatcher is IbcDispatcher, Ownable {
IbcReceiver portAddress,
string calldata version,
ChannelOrder ordering,
bool feeEnabled,
string[] calldata connectionHops,
CounterParty calldata counterparty,
Proof calldata proof
Expand Down Expand Up @@ -404,6 +406,7 @@ contract Dispatcher is IbcDispatcher, Ownable {
string memory selectedVersion = portAddress.onOpenIbcChannel(
version,
ordering,
feeEnabled,
connectionHops,
counterparty.portId,
counterparty.channelId,
Expand All @@ -414,6 +417,7 @@ contract Dispatcher is IbcDispatcher, Ownable {
address(portAddress),
selectedVersion,
ordering,
feeEnabled,
connectionHops,
counterparty.portId,
counterparty.channelId
Expand All @@ -430,6 +434,7 @@ contract Dispatcher is IbcDispatcher, Ownable {
bytes32 channelId,
string[] calldata connectionHops,
ChannelOrder ordering,
bool feeEnabled,
string calldata counterpartyPortId,
bytes32 counterpartyChannelId,
string calldata counterpartyVersion,
Expand All @@ -451,6 +456,7 @@ contract Dispatcher is IbcDispatcher, Ownable {
portChannelMap[address(portAddress)][channelId] = Channel(
counterpartyVersion, // TODO: this should be self version instead of counterparty version
ordering,
feeEnabled,
connectionHops,
counterpartyPortId,
counterpartyChannelId
Expand Down Expand Up @@ -560,6 +566,8 @@ contract Dispatcher is IbcDispatcher, Ownable {
/**
* Pay extra fees for a packet that has already been sent.
* Dapps should call this function to incentivize packet relay if the packet is not ack'ed or timed out yet.
* @notice This function can be called multiple times for the same packet. But it shouldn't be called if the
* channel is not incentivized.
*/
function payPacketFeeAsync(
address portAddress,
Expand Down Expand Up @@ -616,6 +624,8 @@ contract Dispatcher is IbcDispatcher, Ownable {

// enforce ack'ed packet sequences always increment by 1 for ordered channels
Channel memory channel = portChannelMap[address(receiver)][packet.src.channelId];
require(!channel.feeEnabled, 'invalid channel type: incentivized');

if (channel.ordering == ChannelOrder.ORDERED) {
require(
packet.sequence == nextSequenceAck[address(receiver)][packet.src.channelId],
Expand Down Expand Up @@ -659,6 +669,7 @@ contract Dispatcher is IbcDispatcher, Ownable {

// enforce ack'ed packet sequences always increment by 1 for ordered channels
Channel memory channel = portChannelMap[address(receiver)][packet.src.channelId];
require(channel.feeEnabled, 'invalid channel type: non-incentivized');
if (channel.ordering == ChannelOrder.ORDERED) {
require(
packet.sequence == nextSequenceAck[address(receiver)][packet.src.channelId],
Expand Down
1 change: 1 addition & 0 deletions contracts/Ibc.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ enum ChannelOrder {
struct Channel {
string version;
ChannelOrder ordering;
bool feeEnabled;
string[] connectionHops;
string counterpartyPortId;
bytes32 counterpartyChannelId;
Expand Down
1 change: 1 addition & 0 deletions contracts/IbcReceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ interface IbcReceiver {
function onOpenIbcChannel(
string calldata version,
ChannelOrder ordering,
bool feeEnabled,
string[] calldata connectionHops,
string calldata counterpartyPortId,
bytes32 counterpartyChannelId,
Expand Down
1 change: 1 addition & 0 deletions contracts/Mars.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ contract Mars is IbcReceiver, Ownable {
function onOpenIbcChannel(
string calldata version,
ChannelOrder ordering,
bool feeEnabled,
string[] calldata connectionHops,
string calldata counterpartyPortId,
bytes32 counterpartyChannelId,
Expand Down
99 changes: 91 additions & 8 deletions test/Dispatcher.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ contract Base is Test {
address indexed portAddress,
string version,
ChannelOrder ordering,
bool feeEnabled,
string[] connectionHops,
string counterpartyPortId,
bytes32 counterpartyChannelId
Expand Down Expand Up @@ -253,6 +254,7 @@ contract ChannelTestBase is Test, Base {
string[] connectionHops;
VersionSet version = VersionSet('1.0', '1.0', '1.0');
ChannelOrder ordering = ChannelOrder.ORDERED;
bool feeEnabled = false;
CounterParty cp;

CounterParty cpBsc = CounterParty('polyibc.bsc.9876543210', bytes32('channel-99'), '1.0');
Expand Down Expand Up @@ -316,8 +318,24 @@ contract ChannelTestBase is Test, Base {
contract DispatcherOpenIbcChannelTest is ChannelTestBase {
function test_success() public goodCases {
vm.expectEmit(true, true, true, true);
emit OpenIbcChannel(address(mars), version.expected, ordering, connectionHops, cp.portId, cp.channelId);
dispatcher.openIbcChannel(IbcReceiver(mars), version.self, ordering, connectionHops, cp, polymerProof);
emit OpenIbcChannel(
address(mars),
version.expected,
ordering,
feeEnabled,
connectionHops,
cp.portId,
cp.channelId
);
dispatcher.openIbcChannel(
IbcReceiver(mars),
version.self,
ordering,
feeEnabled,
connectionHops,
cp,
polymerProof
);
}

modifier unsupportedVersions() {
Expand Down Expand Up @@ -345,7 +363,15 @@ contract DispatcherOpenIbcChannelTest is ChannelTestBase {

function test_unsupportedVersion() public unsupportedVersions {
vm.expectRevert(bytes('Unsupported version'));
dispatcher.openIbcChannel(IbcReceiver(mars), version.self, ordering, connectionHops, cp, polymerProof);
dispatcher.openIbcChannel(
IbcReceiver(mars),
version.self,
ordering,
feeEnabled,
connectionHops,
cp,
polymerProof
);
}

function test_invalidCounterpartyPortId() public {
Expand All @@ -358,19 +384,43 @@ contract DispatcherOpenIbcChannelTest is ChannelTestBase {
for (uint i = 0; i < cps.length; i++) {
cp = cps[i];
vm.expectRevert('Invalid counterpartyPortId');
dispatcher.openIbcChannel(IbcReceiver(mars), version.self, ordering, connectionHops, cp, polymerProof);
dispatcher.openIbcChannel(
IbcReceiver(mars),
version.self,
ordering,
feeEnabled,
connectionHops,
cp,
polymerProof
);
}
}

function test_invalidProof() public {
vm.expectRevert('Fail to prove channel state');
dispatcher.openIbcChannel(IbcReceiver(mars), '', ChannelOrder.ORDERED, connectionHops, cpBsc, invalidProof);
dispatcher.openIbcChannel(
IbcReceiver(mars),
'',
ChannelOrder.ORDERED,
feeEnabled,
connectionHops,
cpBsc,
invalidProof
);
}
}

contract DispatcherConnectIbcChannelTest is ChannelTestBase {
function test_success() public goodCases {
dispatcher.openIbcChannel(IbcReceiver(mars), version.self, ordering, connectionHops, cp, polymerProof);
dispatcher.openIbcChannel(
IbcReceiver(mars),
version.self,
ordering,
feeEnabled,
connectionHops,
cp,
polymerProof
);
string memory cpVersion = keccak256(abi.encode(cp.version)) == keccak256(abi.encode(bytes('')))
? version.self
: cp.version;
Expand All @@ -383,6 +433,7 @@ contract DispatcherConnectIbcChannelTest is ChannelTestBase {
channelId,
connectionHops,
ordering,
feeEnabled,
cpBsc.portId,
bytes32('channel-99'),
cpVersion,
Expand All @@ -391,7 +442,15 @@ contract DispatcherConnectIbcChannelTest is ChannelTestBase {
}

function test_unsupportedVersions() public goodCases {
dispatcher.openIbcChannel(IbcReceiver(mars), version.self, ordering, connectionHops, cp, polymerProof);
dispatcher.openIbcChannel(
IbcReceiver(mars),
version.self,
ordering,
feeEnabled,
connectionHops,
cp,
polymerProof
);
string memory cpVersion = 'xxx';

vm.expectRevert('Unsupported version');
Expand All @@ -400,6 +459,7 @@ contract DispatcherConnectIbcChannelTest is ChannelTestBase {
bytes32('channel-1'),
connectionHops,
ordering,
feeEnabled,
cp.portId,
bytes32('channel-99'),
cpVersion,
Expand All @@ -414,6 +474,7 @@ contract DispatcherConnectIbcChannelTest is ChannelTestBase {
bytes32('channel-1'),
connectionHops,
ordering,
feeEnabled,
cpBsc.portId,
cpBsc.channelId,
cpBsc.version,
Expand All @@ -427,6 +488,7 @@ contract ChannelOpenTestBase is Test, Base {
Mars mars;
bytes32 channelId = 'channel-1';
address relayer = deriveAddress('relayer');
bool feeEnabled = false;

function setUp() public virtual {
string[] memory connectionHops = new string[](2);
Expand All @@ -448,14 +510,23 @@ contract ChannelOpenTestBase is Test, Base {

// finish channel handshake as chain A
CounterParty memory cp = CounterParty('polyibc.bsc.9876543210', bytes32(0x0), '');
dispatcher.openIbcChannel(IbcReceiver(mars), '1.0', ChannelOrder.ORDERED, connectionHops, cp, emptyProof);
dispatcher.openIbcChannel(
IbcReceiver(mars),
'1.0',
ChannelOrder.ORDERED,
feeEnabled,
connectionHops,
cp,
emptyProof
);
CounterParty memory cp2 = CounterParty('polyibc.bsc.9876543210', bytes32('channel-99'), '1.0');

dispatcher.connectIbcChannel(
IbcReceiver(mars),
channelId,
connectionHops,
ChannelOrder.ORDERED,
feeEnabled,
cp2.portId,
cp2.channelId,
cp2.version,
Expand Down Expand Up @@ -775,6 +846,18 @@ contract DispatcherAckPacketTest is PacketSenderTest {
vm.expectRevert('Packet commitment not found');
dispatcher.acknowledgement(IbcReceiver(mars), packet, ackPacket, validProof);
}

function test_no_incentivizedAck() public {
sendPacket();
IncentivizedAckPacket memory incAck = IncentivizedAckPacket(
true,
abi.encodePacked(deriveAddress('foward-relayer')),
bytes('ack')
);

vm.expectRevert('invalid channel type: non-incentivized');
dispatcher.incentivizedAcknowledgement(IbcReceiver(mars), sentPacket, incAck, validProof);
}
}

// Test Chain A receives a timeout packet from Chain B
Expand Down
13 changes: 13 additions & 0 deletions test/fee.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ contract FeeTest is PacketSenderTest {

PacketFee[] packetFees;

function setUp() public override {
feeEnabled = true;
super.setUp();
}

modifier useFeeTestCases() {
// initialize an array of PacketFee with different values
packetFees.push(PacketFee(0, 0, 0));
Expand Down Expand Up @@ -72,6 +77,14 @@ contract FeeTest is PacketSenderTest {
);
}

// call to acknowledgement fails if the channel is incentivized
function test_must_incentivizedAck() public useFeeTestCases {
vm.startPrank(relayer);
sendPacket();
vm.expectRevert('invalid channel type: incentivized');
dispatcher.acknowledgement(IbcReceiver(mars), sentPacket, ackPacket, validProof);
}

// claim ack fee on receving ack
function test_ack_fee() public useFeeTestCases {
// save balances of forward and reverse relayer payees; assert balances changes after ack
Expand Down

0 comments on commit 78c3168

Please sign in to comment.