Skip to content

Commit

Permalink
feat: allow direct packet packets for ics20 transfer (#113)
Browse files Browse the repository at this point in the history
  • Loading branch information
gjermundgaraba authored Nov 21, 2024
1 parent 152b783 commit 5d6ea88
Show file tree
Hide file tree
Showing 31 changed files with 651 additions and 173 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ jobs:
- TestWithIbcEurekaTestSuite/TestICS20TransferERC20TokenfromEthereumToCosmosAndBack_Groth16
- TestWithIbcEurekaTestSuite/TestICS20TransferERC20TokenfromEthereumToCosmosAndBack_Plonk
- TestWithIbcEurekaTestSuite/Test_25_ICS20TransferERC20TokenfromEthereumToCosmosAndBack_Groth16
- TestWithIbcEurekaTestSuite/Test_100_ICS20TransferERC20TokenfromEthereumToCosmosAndBack_Plonk
- TestWithIbcEurekaTestSuite/Test_50_ICS20TransferERC20TokenfromEthereumToCosmosAndBack_Groth16
- TestWithIbcEurekaTestSuite/Test_50_ICS20TransferERC20TokenfromEthereumToCosmosAndBack_Plonk
- TestWithIbcEurekaTestSuite/TestICS20TransferNativeCosmosCoinsToEthereumAndBack_Groth16
- TestWithIbcEurekaTestSuite/TestICS20TransferNativeCosmosCoinsToEthereumAndBack_Plonk
- TestWithIbcEurekaTestSuite/TestICS20TransferTimeoutFromEthereumToCosmosChain_Groth16
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,21 +131,21 @@ The following benchmarks are for a single packet transfer without aggregation.

| **Contract** | **Method** | **Description** | **Gas (groth16)** | **Gas (plonk)** |
|:---:|:---:|:---:|:---:|:---:|
| `ICS20Transfer.sol` | `sendTransfer` | Initiating an IBC transfer with an `ERC20`. | 251,148 | 251,148 |
| `ICS26Router.sol` | `recvPacket` | Receiving _back_ an `ERC20` token. | 550,874 | 638,731 |
| `ICS26Router.sol` | `recvPacket` | Receiving a _new_ Cosmos token for the first time. (Deploying an `ERC20` contract) | 1,436,745 | 1,524,820 |
| `ICS26Router.sol` | `ackPacket` | Acknowledging an ICS20 packet. | 425,486 | 513,522 |
| `ICS26Router.sol` | `timeoutPacket` | Timing out an ICS20 packet | 470,422 | 558,973 |
| `ICS26Router.sol` | `sendPacket` | Initiating an IBC transfer with an `ERC20`. | ~225,000 | ~225,000 |
| `ICS26Router.sol` | `recvPacket` | Receiving _back_ an `ERC20` token. | ~510,000 | ~588,000 |
| `ICS26Router.sol` | `recvPacket` | Receiving a _new_ Cosmos token for the first time. (Deploying an `ERC20` contract) | ~1,439,000 | ~1,527,000 |
| `ICS26Router.sol` | `ackPacket` | Acknowledging an ICS20 packet. | ~455,000 | ~533,000 |
| `ICS26Router.sol` | `timeoutPacket` | Timing out an ICS20 packet | ~480,000 | ~571,000 |

### Aggregated Packet Benchmarks

The gas costs are substantially lower when aggregating multiple packets into a single proof, as long as the packets are submitted in the same tx.
Since there is no meaningful difference in gas costs between plonk and groth16 in the aggregated case, they are not separated in the table below.

| **ICS26Router Method** | **Description** | **Avg Gas (25 packets)** | **Avg Gas (100 packets)** |
| **ICS26Router Method** | **Description** | **Avg Gas (25 packets)** | **Avg Gas (50 packets)** |
|:---:|:---:|:---:|:---:|
| `multicall/recvPacket` | Receiving _back_ an `ERC20` token. | 226,083 | 217,645 |
| `multicall/ackPacket` | Acknowledging an ICS20 packet. | 128,376 | 121,024 |
| `multicall/recvPacket` | Receiving _back_ an `ERC20` token. | ~228,000 | ~220,000 |
| `multicall/ackPacket` | Acknowledging an ICS20 packet. | ~141,000 | ~135,000 |

## License

Expand Down
105 changes: 105 additions & 0 deletions abi/ICS20Transfer.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,111 @@
],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "newMsgSendPacketV1",
"inputs": [
{
"name": "sender",
"type": "address",
"internalType": "address"
},
{
"name": "msg_",
"type": "tuple",
"internalType": "struct IICS20TransferMsgs.SendTransferMsg",
"components": [
{
"name": "denom",
"type": "string",
"internalType": "string"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "receiver",
"type": "string",
"internalType": "string"
},
{
"name": "sourceChannel",
"type": "string",
"internalType": "string"
},
{
"name": "destPort",
"type": "string",
"internalType": "string"
},
{
"name": "timeoutTimestamp",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "memo",
"type": "string",
"internalType": "string"
}
]
}
],
"outputs": [
{
"name": "",
"type": "tuple",
"internalType": "struct IICS26RouterMsgs.MsgSendPacket",
"components": [
{
"name": "sourceChannel",
"type": "string",
"internalType": "string"
},
{
"name": "timeoutTimestamp",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "payloads",
"type": "tuple[]",
"internalType": "struct IICS26RouterMsgs.Payload[]",
"components": [
{
"name": "sourcePort",
"type": "string",
"internalType": "string"
},
{
"name": "destPort",
"type": "string",
"internalType": "string"
},
{
"name": "version",
"type": "string",
"internalType": "string"
},
{
"name": "encoding",
"type": "string",
"internalType": "string"
},
{
"name": "value",
"type": "bytes",
"internalType": "bytes"
}
]
}
]
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "onAcknowledgementPacket",
Expand Down
11 changes: 6 additions & 5 deletions abi/ICS26Router.json
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,12 @@
],
"anonymous": false
},
{
"type": "event",
"name": "Noop",
"inputs": [],
"anonymous": false
},
{
"type": "event",
"name": "OwnershipTransferred",
Expand Down Expand Up @@ -946,11 +952,6 @@
"name": "IBCMultiPayloadPacketNotSupported",
"inputs": []
},
{
"type": "error",
"name": "IBCMultiPayloadPacketNotSupported",
"inputs": []
},
{
"type": "error",
"name": "IBCPacketCommitmentMismatch",
Expand Down
114 changes: 79 additions & 35 deletions e2e/interchaintestv8/ibc_eureka_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,9 +309,14 @@ func (s *IbcEurekaTestSuite) Test_25_ICS20TransferERC20TokenfromEthereumToCosmos
s.ICS20TransferERC20TokenfromEthereumToCosmosAndBackTest(ctx, operator.ProofTypeGroth16, 25)
}

func (s *IbcEurekaTestSuite) Test_100_ICS20TransferERC20TokenfromEthereumToCosmosAndBack_Plonk() {
func (s *IbcEurekaTestSuite) Test_50_ICS20TransferERC20TokenfromEthereumToCosmosAndBack_Groth16() {
ctx := context.Background()
s.ICS20TransferERC20TokenfromEthereumToCosmosAndBackTest(ctx, operator.ProofTypePlonk, 100)
s.ICS20TransferERC20TokenfromEthereumToCosmosAndBackTest(ctx, operator.ProofTypeGroth16, 50)
}

func (s *IbcEurekaTestSuite) Test_50_ICS20TransferERC20TokenfromEthereumToCosmosAndBack_Plonk() {
ctx := context.Background()
s.ICS20TransferERC20TokenfromEthereumToCosmosAndBackTest(ctx, operator.ProofTypePlonk, 50)
}

// ICS20TransferERC20TokenfromEthereumToCosmosAndBackTest tests the ICS20 transfer functionality by transferring
Expand All @@ -336,8 +341,6 @@ func (s *IbcEurekaTestSuite) ICS20TransferERC20TokenfromEthereumToCosmosAndBackT

ics26routerAbi, err := abi.JSON(strings.NewReader(ics26router.ContractABI))
s.Require().NoError(err)
ics20transferAbi, err := abi.JSON(strings.NewReader(ics20transfer.ContractABI))
s.Require().NoError(err)

s.Require().True(s.Run("Approve the ICS20Transfer.sol contract to spend the erc20 tokens", func() {
tx, err := s.erc20Contract.Approve(s.GetTransactOpts(s.key), ics20Address, totalTransferAmount)
Expand All @@ -355,22 +358,24 @@ func (s *IbcEurekaTestSuite) ICS20TransferERC20TokenfromEthereumToCosmosAndBackT
s.Require().True(s.Run(fmt.Sprintf("Send %d transfers on Ethereum", numOfTransfers), func() {
timeout := uint64(time.Now().Add(30 * time.Minute).Unix())
transferMulticall := make([][]byte, numOfTransfers)
msgSendTransfer := ics20transfer.IICS20TransferMsgsSendTransferMsg{
Denom: s.contractAddresses.Erc20,
Amount: transferAmount,
Receiver: cosmosUserAddress,
SourceChannel: s.TendermintLightClientID,
DestPort: transfertypes.PortID,
TimeoutTimestamp: timeout,
Memo: "",
}
encodedMsg, err := ics20transferAbi.Pack("sendTransfer", msgSendTransfer)

msgSendPacket := s.createICS20MsgSendPacket(
ethereumUserAddress,
s.contractAddresses.Erc20,
transferAmount,
cosmosUserAddress,
s.TendermintLightClientID,
timeout,
"",
)

encodedMsg, err := ics26routerAbi.Pack("sendPacket", msgSendPacket)
s.Require().NoError(err)
for i := 0; i < numOfTransfers; i++ {
transferMulticall[i] = encodedMsg
}

tx, err := s.ics20Contract.Multicall(s.GetTransactOpts(s.key), transferMulticall)
tx, err := s.ics26Contract.Multicall(s.GetTransactOpts(s.key), transferMulticall)
s.Require().NoError(err)
receipt := s.GetTxReciept(ctx, eth, tx.Hash())
s.Require().Equal(ethtypes.ReceiptStatusSuccessful, receipt.Status)
Expand Down Expand Up @@ -944,17 +949,17 @@ func (s *IbcEurekaTestSuite) ICS20TransferNativeCosmosCoinsToEthereumAndBackTest
var sendBlockNumber int64
s.Require().True(s.Run("Transfer tokens back from Ethereum", func() {
timeout := uint64(time.Now().Add(30 * time.Minute).Unix())
msgSendTransfer := ics20transfer.IICS20TransferMsgsSendTransferMsg{
Denom: ibcERC20Address,
Amount: transferAmount,
Receiver: cosmosUserAddress,
SourceChannel: s.TendermintLightClientID,
DestPort: transfertypes.PortID,
TimeoutTimestamp: timeout,
Memo: returnMemo,
}
msgSendPacket := s.createICS20MsgSendPacket(
ethereumUserAddress,
ibcERC20Address,
transferAmount,
cosmosUserAddress,
s.TendermintLightClientID,
timeout,
returnMemo,
)

tx, err := s.ics20Contract.SendTransfer(s.GetTransactOpts(s.key), msgSendTransfer)
tx, err := s.ics26Contract.SendPacket(s.GetTransactOpts(s.key), msgSendPacket)
s.Require().NoError(err)
receipt := s.GetTxReciept(ctx, eth, tx.Hash())
s.Require().Equal(ethtypes.ReceiptStatusSuccessful, receipt.Status)
Expand Down Expand Up @@ -1104,17 +1109,18 @@ func (s *IbcEurekaTestSuite) ICS20TransferTimeoutFromEthereumToCosmosChainTest(c
var timeout uint64
s.Require().True(s.Run("Send transfer on Ethereum", func() {
timeout = uint64(time.Now().Add(30 * time.Second).Unix())
msgSendTransfer := ics20transfer.IICS20TransferMsgsSendTransferMsg{
Denom: s.contractAddresses.Erc20,
Amount: transferAmount,
Receiver: cosmosUserAddress,
SourceChannel: s.TendermintLightClientID,
DestPort: "transfer",
TimeoutTimestamp: timeout,
Memo: "testmemo",
}

tx, err := s.ics20Contract.SendTransfer(s.GetTransactOpts(s.key), msgSendTransfer)
msgSendPacket := s.createICS20MsgSendPacket(
ethereumUserAddress,
s.contractAddresses.Erc20,
transferAmount,
cosmosUserAddress,
s.TendermintLightClientID,
timeout,
"testmemo",
)

tx, err := s.ics26Contract.SendPacket(s.GetTransactOpts(s.key), msgSendPacket)
s.Require().NoError(err)
receipt := s.GetTxReciept(ctx, eth, tx.Hash())
s.Require().Equal(ethtypes.ReceiptStatusSuccessful, receipt.Status)
Expand Down Expand Up @@ -1189,6 +1195,44 @@ func (s *IbcEurekaTestSuite) ICS20TransferTimeoutFromEthereumToCosmosChainTest(c
}))
}

func (s *IbcEurekaTestSuite) createICS20MsgSendPacket(
sender ethcommon.Address,
denom string,
amount *big.Int,
receiver string,
sourceChannel string,
timeoutTimestamp uint64,
memo string,
) ics26router.IICS26RouterMsgsMsgSendPacket {
msgSendTransfer := ics20transfer.IICS20TransferMsgsSendTransferMsg{
Denom: denom,
Amount: amount,
Receiver: receiver,
SourceChannel: sourceChannel,
DestPort: transfertypes.PortID,
TimeoutTimestamp: timeoutTimestamp,
Memo: memo,
}
msgSendPacket, err := s.ics20Contract.ContractCaller.NewMsgSendPacketV1(nil, sender, msgSendTransfer)
s.Require().NoError(err)

// Because of the way abi generation work, the type returned by ics20 is ics20transfer.IICS26RouterMsgsMsgSendPacket
// So we just move the values over here:
return ics26router.IICS26RouterMsgsMsgSendPacket{
SourceChannel: sourceChannel,
TimeoutTimestamp: timeoutTimestamp,
Payloads: []ics26router.IICS26RouterMsgsPayload{
{
SourcePort: msgSendPacket.Payloads[0].SourcePort,
DestPort: msgSendPacket.Payloads[0].DestPort,
Version: msgSendPacket.Payloads[0].Version,
Encoding: msgSendPacket.Payloads[0].Encoding,
Value: msgSendPacket.Payloads[0].Value,
},
},
}
}

func (s *IbcEurekaTestSuite) getCommitmentProof(path []byte) []byte {
eth, simd := s.ChainA, s.ChainB

Expand Down
Loading

0 comments on commit 5d6ea88

Please sign in to comment.