Skip to content

Commit

Permalink
feat: integrate authenticated calls smart contract functionality into…
Browse files Browse the repository at this point in the history
… protocol (#2904)

* e2e tests and modifications for authenticated call

* extend test with sender check and revert case

* separate tests into separate files

* cleanup

* withdraw and call support and tests

* bump protocol contracts

* split tests into separate files

* small cleanup

* fmt

* generate

* lint

* changelog

* PR  comments

* fix case in proto

* bump vote inbound gas limit in zetaclient

* fix test

* generate

* fixing tests

* call options non empty

* generate

* test fix

* rename gateway caller

* pr comments rename tests

* PR comment

* generate

* tests

* update tests fixes

* tests fixes

* fix

* test fix
  • Loading branch information
skosito authored Sep 27, 2024
1 parent 2892114 commit 1712cb0
Show file tree
Hide file tree
Showing 71 changed files with 2,620 additions and 478 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* [2883](https://github.com/zeta-chain/node/pull/2883) - add chain static information for btc signet testnet
* [2907](https://github.com/zeta-chain/node/pull/2907) - derive Bitcoin tss address by chain id and added more Signet static info
* [2911](https://github.com/zeta-chain/node/pull/2911) - add chain static information for btc testnet4
* [2904](https://github.com/zeta-chain/node/pull/2904) - integrate authenticated calls smart contract functionality into protocol

### Refactor

Expand Down
4 changes: 4 additions & 0 deletions cmd/zetae2e/local/v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ func startV2Tests(eg *errgroup.Group, conf config.Config, deployerRunner *runner
e2etests.TestV2ETHDepositName,
e2etests.TestV2ETHDepositAndCallName,
e2etests.TestV2ETHWithdrawName,
e2etests.TestV2ETHWithdrawAndArbitraryCallName,
e2etests.TestV2ETHWithdrawAndCallName,
e2etests.TestV2ETHWithdrawAndCallThroughContractName,
e2etests.TestV2ZEVMToEVMArbitraryCallName,
e2etests.TestV2ZEVMToEVMCallName,
e2etests.TestV2ZEVMToEVMCallThroughContractName,
e2etests.TestV2EVMToZEVMCallName,
))

Expand Down
2 changes: 1 addition & 1 deletion docs/cli/zetacored/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -9441,7 +9441,7 @@ zetacored tx crosschain vote-gas-price [chain] [price] [priorityFee] [blockNumbe
Broadcast message to vote an inbound

```
zetacored tx crosschain vote-inbound [sender] [senderChainID] [txOrigin] [receiver] [receiverChainID] [amount] [message] [inboundHash] [inBlockHeight] [coinType] [asset] [eventIndex] [protocolContractVersion] [flags]
zetacored tx crosschain vote-inbound [sender] [senderChainID] [txOrigin] [receiver] [receiverChainID] [amount] [message] [inboundHash] [inBlockHeight] [coinType] [asset] [eventIndex] [protocolContractVersion] [isArbitraryCall] [flags]
```

### Options
Expand Down
11 changes: 11 additions & 0 deletions docs/openapi/openapi.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57066,6 +57066,14 @@ definitions:
- ERC20: ERC20 token
- Cmd: no asset, used for admin command
- NoAssetCall: no asset, used for contract call
crosschainCallOptions:
type: object
properties:
gas_limit:
type: string
format: uint64
is_arbitrary_call:
type: boolean
crosschainCctxStatus:
type: string
enum:
Expand Down Expand Up @@ -57276,6 +57284,7 @@ definitions:
gas_limit:
type: string
format: uint64
title: Deprecated (v21), use CallOptions
gas_price:
type: string
gas_priority_fee:
Expand All @@ -57302,6 +57311,8 @@ definitions:
type: string
tx_finalization_status:
$ref: '#/definitions/crosschainTxFinalizationStatus'
call_options:
$ref: '#/definitions/crosschainCallOptions'
crosschainOutboundTracker:
type: object
properties:
Expand Down
1 change: 1 addition & 0 deletions docs/spec/crosschain/messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ message MsgVoteInbound {
uint64 event_index = 15;
ProtocolContractVersion protocol_contract_version = 16;
RevertOptions revert_options = 17;
CallOptions call_options = 18;
}
```

Expand Down
34 changes: 33 additions & 1 deletion e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ const (
TestV2ETHDepositAndCallRevertName = "v2_eth_deposit_and_call_revert"
TestV2ETHDepositAndCallRevertWithCallName = "v2_eth_deposit_and_call_revert_with_call"
TestV2ETHWithdrawName = "v2_eth_withdraw"
TestV2ETHWithdrawAndArbitraryCallName = "v2_eth_withdraw_and_arbitrary_call"
TestV2ETHWithdrawAndCallName = "v2_eth_withdraw_and_call"
TestV2ETHWithdrawAndCallThroughContractName = "v2_eth_withdraw_and_call_through_contract"
TestV2ETHWithdrawAndCallRevertName = "v2_eth_withdraw_and_call_revert"
TestV2ETHWithdrawAndCallRevertWithCallName = "v2_eth_withdraw_and_call_revert_with_call"
TestV2ERC20DepositName = "v2_erc20_deposit"
Expand All @@ -142,7 +144,9 @@ const (
TestV2ERC20WithdrawAndCallName = "v2_erc20_withdraw_and_call"
TestV2ERC20WithdrawAndCallRevertName = "v2_erc20_withdraw_and_call_revert"
TestV2ERC20WithdrawAndCallRevertWithCallName = "v2_erc20_withdraw_and_call_revert_with_call"
TestV2ZEVMToEVMArbitraryCallName = "v2_zevm_to_evm_arbitrary_call"
TestV2ZEVMToEVMCallName = "v2_zevm_to_evm_call"
TestV2ZEVMToEVMCallThroughContractName = "v2_zevm_to_evm_call_through_contract"
TestV2EVMToZEVMCallName = "v2_evm_to_zevm_call"

/*
Expand Down Expand Up @@ -731,13 +735,29 @@ var AllE2ETests = []runner.E2ETest{
TestV2ETHWithdraw,
),
runner.NewE2ETest(
TestV2ETHWithdrawAndCallName,
TestV2ETHWithdrawAndArbitraryCallName,
"withdraw Ether from ZEVM and call a contract using V2 contract",
[]runner.ArgDefinition{
{Description: "amount in wei", DefaultValue: "100000"},
},
TestV2ETHWithdrawAndArbitraryCall,
),
runner.NewE2ETest(
TestV2ETHWithdrawAndCallName,
"withdraw Ether from ZEVM call a contract using V2 contract",
[]runner.ArgDefinition{
{Description: "amount in wei", DefaultValue: "100000"},
},
TestV2ETHWithdrawAndCall,
),
runner.NewE2ETest(
TestV2ETHWithdrawAndCallThroughContractName,
"withdraw Ether from ZEVM call a contract using V2 contract through intermediary contract",
[]runner.ArgDefinition{
{Description: "amount in wei", DefaultValue: "100000"},
},
TestV2ETHWithdrawAndCallThroughContract,
),
runner.NewE2ETest(
TestV2ETHWithdrawAndCallRevertName,
"withdraw Ether from ZEVM and call a contract using V2 contract that reverts",
Expand Down Expand Up @@ -818,12 +838,24 @@ var AllE2ETests = []runner.E2ETest{
},
TestV2ERC20WithdrawAndCallRevertWithCall,
),
runner.NewE2ETest(
TestV2ZEVMToEVMArbitraryCallName,
"zevm -> evm call using V2 contract",
[]runner.ArgDefinition{},
TestV2ZEVMToEVMArbitraryCall,
),
runner.NewE2ETest(
TestV2ZEVMToEVMCallName,
"zevm -> evm call using V2 contract",
[]runner.ArgDefinition{},
TestV2ZEVMToEVMCall,
),
runner.NewE2ETest(
TestV2ZEVMToEVMCallThroughContractName,
"zevm -> evm call using V2 contract through intermediary contract",
[]runner.ArgDefinition{},
TestV2ZEVMToEVMCallThroughContract,
),
runner.NewE2ETest(
TestV2EVMToZEVMCallName,
"evm -> zevm call using V2 contract",
Expand Down
40 changes: 40 additions & 0 deletions e2e/e2etests/test_v2_eth_withdraw_and_arbitrary_call.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package e2etests

import (
"math/big"

"github.com/stretchr/testify/require"
"github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol"

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/utils"
crosschaintypes "github.com/zeta-chain/node/x/crosschain/types"
)

const payloadMessageWithdrawETH = "this is a test ETH withdraw and call payload"

func TestV2ETHWithdrawAndArbitraryCall(r *runner.E2ERunner, args []string) {
require.Len(r, args, 1)

amount, ok := big.NewInt(0).SetString(args[0], 10)
require.True(r, ok, "Invalid amount specified for TestV2ETHWithdrawAndCall")

r.AssertTestDAppEVMCalled(false, payloadMessageWithdrawETH, amount)

r.ApproveETHZRC20(r.GatewayZEVMAddr)

// perform the withdraw
tx := r.V2ETHWithdrawAndCall(
r.TestDAppV2EVMAddr,
amount,
r.EncodeGasCall(payloadMessageWithdrawETH),
gatewayzevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)},
)

// wait for the cctx to be mined
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "withdraw")
require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status)

r.AssertTestDAppEVMCalled(true, payloadMessageWithdrawETH, amount)
}
30 changes: 25 additions & 5 deletions e2e/e2etests/test_v2_eth_withdraw_and_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package e2etests
import (
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol"

Expand All @@ -11,23 +12,34 @@ import (
crosschaintypes "github.com/zeta-chain/node/x/crosschain/types"
)

const payloadMessageWithdrawETH = "this is a test ETH withdraw and call payload"
const payloadMessageAuthenticatedWithdrawETH = "this is a test ETH withdraw and authenticated call payload"

func TestV2ETHWithdrawAndCall(r *runner.E2ERunner, args []string) {
require.Len(r, args, 1)

previousGasLimit := r.ZEVMAuth.GasLimit
r.ZEVMAuth.GasLimit = 10000000
defer func() {
r.ZEVMAuth.GasLimit = previousGasLimit
}()

amount, ok := big.NewInt(0).SetString(args[0], 10)
require.True(r, ok, "Invalid amount specified for TestV2ETHWithdrawAndCall")

r.AssertTestDAppEVMCalled(false, payloadMessageWithdrawETH, amount)
r.AssertTestDAppEVMCalled(false, payloadMessageAuthenticatedWithdrawETH, amount)

r.ApproveETHZRC20(r.GatewayZEVMAddr)

// set expected sender
tx, err := r.TestDAppV2EVM.SetExpectedOnCallSender(r.EVMAuth, r.ZEVMAuth.From)
require.NoError(r, err)
utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout)

// perform the withdraw
tx := r.V2ETHWithdrawAndCall(
tx = r.V2ETHWithdrawAndAuthenticatedCall(
r.TestDAppV2EVMAddr,
amount,
r.EncodeGasCall(payloadMessageWithdrawETH),
[]byte(payloadMessageAuthenticatedWithdrawETH),
gatewayzevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)},
)

Expand All @@ -36,5 +48,13 @@ func TestV2ETHWithdrawAndCall(r *runner.E2ERunner, args []string) {
r.Logger.CCTX(*cctx, "withdraw")
require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status)

r.AssertTestDAppEVMCalled(true, payloadMessageWithdrawETH, amount)
r.AssertTestDAppEVMCalled(true, payloadMessageAuthenticatedWithdrawETH, amount)

// check expected sender was used
senderForMsg, err := r.TestDAppV2EVM.SenderWithMessage(
&bind.CallOpts{},
[]byte(payloadMessageAuthenticatedWithdrawETH),
)
require.NoError(r, err)
require.Equal(r, r.ZEVMAuth.From, senderForMsg)
}
84 changes: 84 additions & 0 deletions e2e/e2etests/test_v2_eth_withdraw_and_call_through_contract.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package e2etests

import (
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/utils"
gatewayzevmcaller "github.com/zeta-chain/node/pkg/contracts/gatewayzevmcaller"
crosschaintypes "github.com/zeta-chain/node/x/crosschain/types"
)

const payloadMessageAuthenticatedWithdrawETHThroughContract = "this is a test ETH withdraw and authenticated call payload through contract"

func TestV2ETHWithdrawAndCallThroughContract(r *runner.E2ERunner, args []string) {
require.Len(r, args, 1)

previousGasLimit := r.ZEVMAuth.GasLimit
r.ZEVMAuth.GasLimit = 10000000
defer func() {
r.ZEVMAuth.GasLimit = previousGasLimit
}()

amount, ok := big.NewInt(0).SetString(args[0], 10)
require.True(r, ok, "Invalid amount specified for TestV2ETHWithdrawAndCall")

// deploy caller contract and send it gas zrc20 to pay gas fee
gatewayCallerAddr, tx, gatewayCaller, err := gatewayzevmcaller.DeployGatewayZEVMCaller(
r.ZEVMAuth,
r.ZEVMClient,
r.GatewayZEVMAddr,
r.WZetaAddr,
)
require.NoError(r, err)
utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout)

tx, err = r.ETHZRC20.Transfer(r.ZEVMAuth, gatewayCallerAddr, big.NewInt(100000000000000000))
require.NoError(r, err)
utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout)

// set expected sender
tx, err = r.TestDAppV2EVM.SetExpectedOnCallSender(r.EVMAuth, gatewayCallerAddr)
require.NoError(r, err)
utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout)

// perform the authenticated call
tx = r.V2ETHWithdrawAndAuthenticatedCallThroughContract(gatewayCaller, r.TestDAppV2EVMAddr,
amount,
[]byte(payloadMessageAuthenticatedWithdrawETHThroughContract),
gatewayzevmcaller.RevertOptions{OnRevertGasLimit: big.NewInt(0)})

utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout)
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "withdraw")
require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status)

r.AssertTestDAppEVMCalled(true, payloadMessageAuthenticatedWithdrawETHThroughContract, amount)

// check expected sender was used
senderForMsg, err := r.TestDAppV2EVM.SenderWithMessage(
&bind.CallOpts{},
[]byte(payloadMessageAuthenticatedWithdrawETHThroughContract),
)
require.NoError(r, err)
require.Equal(r, gatewayCallerAddr, senderForMsg)

// set expected sender to wrong one
tx, err = r.TestDAppV2EVM.SetExpectedOnCallSender(r.EVMAuth, r.ZEVMAuth.From)
require.NoError(r, err)
utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout)

// repeat authenticated call through contract, should revert because of wrong sender
tx = r.V2ETHWithdrawAndAuthenticatedCallThroughContract(gatewayCaller, r.TestDAppV2EVMAddr,
amount,
[]byte(payloadMessageAuthenticatedWithdrawETHThroughContract),
gatewayzevmcaller.RevertOptions{OnRevertGasLimit: big.NewInt(0)})

utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout)
cctx = utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "withdraw")
require.Equal(r, crosschaintypes.CctxStatus_Reverted, cctx.CctxStatus.Status)
}
36 changes: 36 additions & 0 deletions e2e/e2etests/test_v2_zevm_to_evm_arbitrary_call.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package e2etests

import (
"math/big"

"github.com/stretchr/testify/require"
"github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol"

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/utils"
crosschaintypes "github.com/zeta-chain/node/x/crosschain/types"
)

const payloadMessageEVMCall = "this is a test EVM call payload"

func TestV2ZEVMToEVMArbitraryCall(r *runner.E2ERunner, args []string) {
require.Len(r, args, 0)

r.AssertTestDAppEVMCalled(false, payloadMessageEVMCall, big.NewInt(0))

// Necessary approval for fee payment
r.ApproveETHZRC20(r.GatewayZEVMAddr)

// perform the call
tx := r.V2ZEVMToEMVCall(r.TestDAppV2EVMAddr, r.EncodeSimpleCall(payloadMessageEVMCall), gatewayzevm.RevertOptions{
OnRevertGasLimit: big.NewInt(0),
})

// wait for the cctx to be mined
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "call")
require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status)

// check the payload was received on the contract
r.AssertTestDAppEVMCalled(true, payloadMessageEVMCall, big.NewInt(0))
}
Loading

0 comments on commit 1712cb0

Please sign in to comment.