Skip to content

Commit

Permalink
feat(ucs01): evm: split code and create tests (#814)
Browse files Browse the repository at this point in the history
  • Loading branch information
hussein-aitlahcen authored Oct 16, 2023
2 parents e2bd91d + 62a6501 commit ebf4a70
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 94 deletions.
1 change: 1 addition & 0 deletions evm/contracts/apps/Base.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ abstract contract IBCAppBase is Context, IIBCModule {
function onChanOpenAck(
string calldata portId,
string calldata channelId,
string calldata counterpartyChannelId,
string calldata counterpartyVersion
) external virtual override onlyIBC {}

Expand Down
11 changes: 6 additions & 5 deletions evm/contracts/apps/ucs/00-pingpong/PingPong.sol
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ contract PingPong is IBCAppBase {
function onChanOpenAck(
string calldata _portId,
string calldata _channelId,
string calldata
string calldata _counterpartyChannelId,
string calldata _counterpartyVersion
) external virtual override onlyIBC {
portId = _portId;
channelId = _channelId;
Expand All @@ -168,15 +169,15 @@ contract PingPong is IBCAppBase {
}

function onChanCloseInit(
string calldata,
string calldata
string calldata _portId,
string calldata _channelId
) external virtual override onlyIBC {
revert("This game is infinite");
}

function onChanCloseConfirm(
string calldata,
string calldata
string calldata _portId,
string calldata _channelId
) external virtual override onlyIBC {
revert("This game is infinite");
}
Expand Down
213 changes: 125 additions & 88 deletions evm/contracts/apps/ucs/01-relay/Relay.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,77 @@ struct RelayPacket {
Token[] tokens;
}

library RelayLib {
using LibString for *;

function isRemote(
string memory portId,
string memory channelId,
string memory denom
) public pure returns (bool) {
return
bytes(denom).length > 0 &&
denom.startsWith(makeDenomPrefix(portId, channelId));
}

function makeDenomPrefix(
string memory portId,
string memory channelId
) public pure returns (string memory) {
return string(abi.encodePacked(portId, "/", channelId, "/"));
}

function makeForeignDenom(
string memory portId,
string memory channelId,
string memory denom
) public pure returns (string memory) {
return
string(abi.encodePacked(makeDenomPrefix(portId, channelId), denom));
}

// It expect 0x.. prefix
function hexToAddress(
string memory _a
) internal pure returns (address _parsedAddress) {
bytes memory tmp = bytes(_a);
uint160 iaddr = 0;
uint160 b1;
uint160 b2;
for (uint256 i = 2; i < 2 + 2 * 20; i += 2) {
iaddr *= 256;
b1 = uint160(uint8(tmp[i]));
b2 = uint160(uint8(tmp[i + 1]));
if ((b1 >= 97) && (b1 <= 102)) {
b1 -= 87;
} else if ((b1 >= 65) && (b1 <= 70)) {
b1 -= 55;
} else if ((b1 >= 48) && (b1 <= 57)) {
b1 -= 48;
}
if ((b2 >= 97) && (b2 <= 102)) {
b2 -= 87;
} else if ((b2 >= 65) && (b2 <= 70)) {
b2 -= 55;
} else if ((b2 >= 48) && (b2 <= 57)) {
b2 -= 48;
}
iaddr += (b1 * 16 + b2);
}
return address(iaddr);
}
}

library RelayPacketLib {
function encode(
RelayPacket memory packet
) internal pure returns (bytes memory) {
) public pure returns (bytes memory) {
return abi.encode(packet.sender, packet.receiver, packet.tokens);
}

function decode(
bytes memory packet
) internal pure returns (RelayPacket memory) {
) public pure returns (RelayPacket memory) {
(
string memory sender,
string memory receiver,
Expand Down Expand Up @@ -91,53 +152,6 @@ contract UCS01Relay is IBCAppBase {
return address(ibcHandler);
}

// It expect 0x.. prefix
function hexToAddress(
string memory _a
) internal pure returns (address _parsedAddress) {
bytes memory tmp = bytes(_a);
uint160 iaddr = 0;
uint160 b1;
uint160 b2;
for (uint256 i = 2; i < 2 + 2 * 20; i += 2) {
iaddr *= 256;
b1 = uint160(uint8(tmp[i]));
b2 = uint160(uint8(tmp[i + 1]));
if ((b1 >= 97) && (b1 <= 102)) {
b1 -= 87;
} else if ((b1 >= 65) && (b1 <= 70)) {
b1 -= 55;
} else if ((b1 >= 48) && (b1 <= 57)) {
b1 -= 48;
}
if ((b2 >= 97) && (b2 <= 102)) {
b2 -= 87;
} else if ((b2 >= 65) && (b2 <= 70)) {
b2 -= 55;
} else if ((b2 >= 48) && (b2 <= 57)) {
b2 -= 48;
}
iaddr += (b1 * 16 + b2);
}
return address(iaddr);
}

function makeDenomPrefix(
string memory portId,
string memory channelId
) public view returns (string memory) {
return string(abi.encodePacked(portId, "/", channelId, "/"));
}

function makeForeignDenom(
string memory portId,
string memory channelId,
string memory denom
) public view returns (string memory) {
return
string(abi.encodePacked(makeDenomPrefix(portId, channelId), denom));
}

function increaseOutstanding(
string memory portId,
string memory channelId,
Expand All @@ -160,6 +174,42 @@ contract UCS01Relay is IBCAppBase {
].sub(amount);
}

function sendToken(
string calldata portId,
string calldata channelId,
string memory counterpartyPortId,
string memory counterpartyChannelId,
LocalToken calldata localToken
) internal returns (string memory addressDenom) {
SafeERC20.safeTransferFrom(
IERC20(localToken.denom),
msg.sender,
address(this),
localToken.amount
);
addressDenom = addressToDenom[localToken.denom];
if (
RelayLib.isRemote(
counterpartyPortId,
counterpartyChannelId,
addressDenom
)
) {
IERC20Denom(localToken.denom).burn(
address(this),
localToken.amount
);
} else {
increaseOutstanding(
portId,
channelId,
localToken.denom,
localToken.amount
);
addressDenom = localToken.denom.toHexString();
}
}

function send(
string calldata portId,
string calldata channelId,
Expand All @@ -176,34 +226,13 @@ contract UCS01Relay is IBCAppBase {
// - if the token is remote native, burn the wrapper
for (uint256 i = 0; i < tokens.length; i++) {
LocalToken calldata localToken = tokens[i];
SafeERC20.safeTransferFrom(
IERC20(localToken.denom),
msg.sender,
address(this),
localToken.amount
);
string memory addressDenom = addressToDenom[localToken.denom];
string memory prefix = makeDenomPrefix(
string memory addressDenom = sendToken(
portId,
channelId,
counterparty.port_id,
counterparty.channel_id
counterparty.channel_id,
localToken
);
if (
bytes(addressDenom).length != 0 &&
addressDenom.toSlice().startsWith(prefix.toSlice())
) {
IERC20Denom(localToken.denom).burn(
address(this),
localToken.amount
);
} else {
increaseOutstanding(
portId,
channelId,
localToken.denom,
localToken.amount
);
addressDenom = localToken.denom.toHexString();
}
normalizedTokens[i].denom = addressDenom;
normalizedTokens[i].amount = uint256(localToken.amount);
emit Sent(
Expand All @@ -214,18 +243,21 @@ contract UCS01Relay is IBCAppBase {
uint256(localToken.amount)
);
}
string memory sender = msg.sender.toHexString();
RelayPacket memory packet = RelayPacket({
sender: msg.sender.toHexString(),
receiver: receiver,
tokens: normalizedTokens
});
IbcCoreClientV1Height.Data memory timeoutHeight = IbcCoreClientV1Height
.Data({
revision_number: counterpartyTimeoutRevisionNumber,
revision_height: counterpartyTimeoutRevisionHeight
});
ibcHandler.sendPacket(
portId,
channelId,
IbcCoreClientV1Height.Data({
revision_number: counterpartyTimeoutRevisionNumber,
revision_height: counterpartyTimeoutRevisionHeight
}),
timeoutHeight,
0,
packet.encode()
);
Expand All @@ -237,7 +269,7 @@ contract UCS01Relay is IBCAppBase {
RelayPacket memory packet
) internal {
// We're going to refund, the receiver will be the sender.
address receiver = hexToAddress(packet.sender);
address receiver = RelayLib.hexToAddress(packet.sender);
for (uint256 i = 0; i < packet.tokens.length; i++) {
Token memory token = packet.tokens[i];
// Either we tried to send back a remote native token
Expand All @@ -247,7 +279,7 @@ contract UCS01Relay is IBCAppBase {
IERC20Denom(denomAddress).mint(receiver, token.amount);
} else {
// It must be in the form 0x...
denomAddress = hexToAddress(token.denom);
denomAddress = RelayLib.hexToAddress(token.denom);
decreaseOutstanding(
portId,
channelId,
Expand All @@ -271,7 +303,7 @@ contract UCS01Relay is IBCAppBase {
) public {
require(msg.sender == address(this));
RelayPacket memory packet = RelayPacketLib.decode(ibcPacket.data);
string memory prefix = makeDenomPrefix(
string memory prefix = RelayLib.makeDenomPrefix(
ibcPacket.destination_port,
ibcPacket.destination_channel
);
Expand All @@ -282,12 +314,12 @@ contract UCS01Relay is IBCAppBase {
strings.slice memory trimedDenom = denomSlice.beyond(
prefix.toSlice()
);
address receiver = hexToAddress(packet.receiver);
address receiver = RelayLib.hexToAddress(packet.receiver);
address denomAddress;
string memory denom;
if (!denomSlice.equals(trimedDenom)) {
denom = trimedDenom.toString();
denomAddress = hexToAddress(denom);
denomAddress = RelayLib.hexToAddress(denom);
// The token must be outstanding.
decreaseOutstanding(
ibcPacket.destination_port,
Expand All @@ -297,7 +329,7 @@ contract UCS01Relay is IBCAppBase {
);
IERC20(denomAddress).transfer(receiver, token.amount);
} else {
denom = makeForeignDenom(
denom = RelayLib.makeForeignDenom(
ibcPacket.source_port,
ibcPacket.source_channel,
token.denom
Expand Down Expand Up @@ -400,10 +432,15 @@ contract UCS01Relay is IBCAppBase {
}

function onChanOpenAck(
string calldata _portId,
string calldata _channelId,
string calldata portId,
string calldata channelId,
string calldata counterpartyChannelId,
string calldata _counterpartyVersion
) external virtual override onlyIBC {}
) external virtual override onlyIBC {
// Counterparty channel was empty.
counterpartyEndpoints[portId][channelId]
.channel_id = counterpartyChannelId;
}

function onChanOpenConfirm(
string calldata _portId,
Expand Down
1 change: 1 addition & 0 deletions evm/contracts/core/05-port/IIBCModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ interface IIBCModule {
function onChanOpenAck(
string calldata portId,
string calldata channelId,
string calldata counterpartyChannelId,
string calldata counterpartyVersion
) external;

Expand Down
1 change: 1 addition & 0 deletions evm/contracts/core/25-handler/IBCChannelHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ abstract contract IBCChannelHandler is ModuleManager {
lookupModuleByPort(msg_.portId).onChanOpenAck(
msg_.portId,
msg_.channelId,
msg_.counterpartyChannelId,
msg_.counterpartyVersion
);

Expand Down
7 changes: 6 additions & 1 deletion evm/contracts/core/DevnetIBCHandlerInit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ contract DevnetIBCHandlerInit is IBCHost {
channel.counterparty,
channel.version
);
module.onChanOpenAck(portId, channelId, channel.version);
module.onChanOpenAck(
portId,
channelId,
channel.counterparty.channel_id,
channel.version
);
claimCapability(
channelCapabilityPath(portId, channelId),
address(module)
Expand Down
1 change: 1 addition & 0 deletions evm/tests/src/MockApp.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ contract MockApp is IIBCModule {
function onChanOpenAck(
string calldata portId,
string calldata channelId,
string calldata counterpartyChannelId,
string calldata counterpartyVersion
) external virtual override {}

Expand Down
Loading

0 comments on commit ebf4a70

Please sign in to comment.