Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: replace ics20-1 with ics20-2 #244

Closed
wants to merge 45 commits into from

Conversation

gjermundgaraba
Copy link
Contributor

@gjermundgaraba gjermundgaraba commented Jan 28, 2025

Description

closes: #114
closes: #219
^ let's discuss if this is true, but I think so.

There are a few important things to note about these changes:

  • IBCDenom has been replaced with an internal "Denom ID" used only to map denoms to an IBCERC20 address. See more details below on reasoning.
  • The ICS20Transfer flow has been adjusted and tested for middle chain scenarios and should find correct contracts to interact with for both sending and receiving. I would argue Validate and refactor ICS20 sendPacket flow #219 is not an issue in this repo anymore (if it is, we just need to remove the closes: for 219 above.
  • Additional validation to keep this implementation in line with ibc-go has been added and unit tested.
  • Multi-denom transfers are supported, but not tested properly here. Add tests for multi-denom transfer #249 will handle that
  • Some other changes that are worth to point out are commented directly in the code

I have replaced the IBCDenom format from ibc-go (ibc/{HASH_OF_PATH}) to a more gas effecient alternative. This is not a required format for the spec and while it would be nice to keep the same format as ibc-go, the cost is very different, as can be seen in the table below:

Test case Gas IBC Denom Gas "Denom Identifier"
base only 42566 1440
2 hops 44776 4276

A lot of this is due to the hex string manipulation, but even reducing that would still be at least 17-20k gas.


Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.

  • Linked to GitHub issue with discussion and accepted design, OR link to spec that describes this work.
  • Wrote unit and integration tests.
  • Added relevant natspec and godoc comments.
  • Provide a conventional commit message to follow the repository standards.
  • Re-reviewed Files changed in the GitHub PR explorer.
  • Review SonarCloud Report in the comment section below once CI passes.

@gjermundgaraba gjermundgaraba linked an issue Jan 28, 2025 that may be closed by this pull request
4 tasks
Copy link

codecov bot commented Jan 29, 2025

Codecov Report

Attention: Patch coverage is 99.29078% with 1 line in your changes missing coverage. Please review.

Project coverage is 99.67%. Comparing base (ec5227e) to head (22c85bf).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
contracts/utils/ICS20Lib.sol 98.43% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #244      +/-   ##
==========================================
+ Coverage   99.47%   99.67%   +0.19%     
==========================================
  Files          12       12              
  Lines         572      612      +40     
==========================================
+ Hits          569      610      +41     
+ Misses          3        2       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Hop[] hops;
}

// ICS20Transfer payload data structures:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted to move all these structures here to avoid circular dependencies. It would be possible to keep some in ICS20Lib, but if some need to be here, I thought it was cleaner to just have all the structures here, which is how we have done it other places too.

@@ -19,7 +19,7 @@ func IbcGoChainSpec(name, chainId string) *interchaintest.ChainSpec {
Images: []ibc.DockerImage{
{
Repository: "ghcr.io/cosmos/ibc-go-wasm-simd", // FOR LOCAL IMAGE USE: Docker Image Name
Version: "feat-ibc-eureka", // FOR LOCAL IMAGE USE: Docker Image Tag
Version: "gjermund-update-abi-for-ics20v2", // FOR LOCAL IMAGE USE: Docker Image Tag
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be replaced with the proper one as soon as this is merged and the abigen dependency updated in feat/ibc-eureka.

});

// just to prove that it works with the unaltered transfer message
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I deleted a bunch of tests that were already covered in the integration tests, to keep the maintenance burden down.

string public senderStr;
address public receiver;
string public receiverStr = "someReceiver";
address public defaultSender;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I refactored the integration tests to reduce duplication and to make it easier to reason about which values where used in different scenarios.

@gjermundgaraba gjermundgaraba marked this pull request as ready for review February 1, 2025 16:41
Copy link
Member

@srdtrk srdtrk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will close as not planned for now

@@ -18,7 +18,7 @@ import { MulticallUpgradeable } from "@openzeppelin-upgradeable/utils/MulticallU
import { ICS20Lib } from "./utils/ICS20Lib.sol";
import { IBCERC20 } from "./utils/IBCERC20.sol";
import { Escrow } from "./utils/Escrow.sol";
import { Bytes } from "@openzeppelin-contracts/utils/Bytes.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { Strings } from "@openzeppelin-contracts/utils/Strings.sol";

This shouldn't have worked? At least maybe we should make sure it doesn't?

Comment on lines -177 to +178
| `multicall/recvPacket` | Receiving _back_ an `ERC20` token. | ~185,876 | ~179,615 |
| `multicall/ackPacket` | Acknowledging an ICS20 packet. | ~96,436 | ~90,776 |
| `multicall/recvPacket` | Receiving _back_ an `ERC20` token. | ~185,811 | ~181,461 |
| `multicall/ackPacket` | Acknowledging an ICS20 packet. | ~82,914 | ~78,926 |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why recv packet hasn't changed much but single packet benchmarks improved a lot

/// @notice Get the full denom path of the token
/// @return the full path of the token's denom
function fullDenomPath() external view returns (string memory);
/// @notice Get the full denom of the token
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @notice Get the full denom of the token
/// @notice Get the full IBC denom of the token

This concept shouldn't be confused with ERC20's denom concept, so perhaps the function name should be changed as well

Comment on lines +22 to +23
/// @return The IBCERC20 contract address
function ibcERC20Contract(IICS20TransferMsgs.Denom calldata denom) external view returns (address);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably make a version of this query which simply takes in a string. (For easier interaction/testing with frontends and ibc-go.)

Comment on lines -103 to +104
return _getICS26Router().sendPacket(ICS20Lib.newMsgSendPacketV1(_msgSender(), msg_));
return _getICS26Router().sendPacket(ICS20Lib.newMsgSendPacketV2(_msgSender(), msg_));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this PR closes #219. We decided that we will attempt a full refactor of the send packet flow. So I think that issue should still stay open. (I gave more reasoning later in this review)

/// @param packetData The packet data to validate
/// @return isValid Whether the packet data is valid
/// @return reason The reason for invalidity, empty if valid
// solhint-disable-next-line code-complexity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bad idea imo

{
if (packetData.forwarding.hops.length > 0) {
if (packetData.forwarding.hops.length > MAX_HOPS) {
return (false, "too many hops");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just revert with a custom error instead of returning an error string and returning a bool? I'd much rather prefer that

Comment on lines +257 to +258
IICS20TransferMsgs.Denom memory newDenom =
IICS20TransferMsgs.Denom({ base: denom.base, trace: new IICS20TransferMsgs.Hop[](denom.trace.length - 1) });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so that we don't mutate the initial denom?

Comment on lines +256 to +264
transferPayload := ics20lib.IICS20TransferMsgsFungibleTokenPacketDataV2{
Tokens: []ics20lib.IICS20TransferMsgsToken{
{
Denom: ics20lib.IICS20TransferMsgsDenom{
Base: transferCoin.Denom,
},
Amount: transferCoin.Amount.BigInt(),
},
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is why #219 is not resolved

Comment on lines +135 to +138
if (returningToSource) {
// token is returning to source, it is an IBCERC20 and we must burn the token (not keep it in escrow)
IBCERC20(erc20Address).burn(token.amount);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe an issue for this?

@srdtrk srdtrk closed this Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Validate and refactor ICS20 sendPacket flow Include support for ICS20-v2
2 participants