Skip to content

Commit

Permalink
outbound for gas withdraw
Browse files Browse the repository at this point in the history
  • Loading branch information
lumtis committed Aug 9, 2024
1 parent 1e08033 commit 99cdcf5
Show file tree
Hide file tree
Showing 20 changed files with 290 additions and 72 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ start-solana-test: zetanode solana

start-v2-test: zetanode
@echo "--> Starting e2e smart contracts v2 test"
export E2E_ARGS="--skip-regular --test-v2" && \
export E2E_ARGS="--skip-regular --test-v2 --verbose" && \
cd contrib/localnet/ && $(DOCKER_COMPOSE) -f docker-compose.yml up -d

###############################################################################
Expand Down
8 changes: 4 additions & 4 deletions cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,11 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
if testV2 {
eg.Go(v2TestRoutine(conf, deployerRunner, verbose,
e2etests.TestV2ETHDepositName,
e2etests.TestV2ETHDepositAndCallName,
//e2etests.TestV2ETHWithdrawName,
//e2etests.TestV2ETHDepositAndCallName,
e2etests.TestV2ETHWithdrawName,
//e2etests.TestV2ETHWithdrawAndCallName,
e2etests.TestV2ERC20DepositName,
e2etests.TestV2ERC20DepositAndCallName,
//e2etests.TestV2ERC20DepositName,
//e2etests.TestV2ERC20DepositAndCallName,
//e2etests.TestV2ERC20WithdrawName,
//e2etests.TestV2ERC20WithdrawAndCallName,
//e2etests.TestV2ZEVMToEVMCallName,
Expand Down
2 changes: 1 addition & 1 deletion e2e/e2etests/test_v2_erc20_deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestV2ERC20Deposit(r *runner.E2ERunner, args []string) {
amount, ok := big.NewInt(0).SetString(args[0], 10)
require.True(r, ok, "Invalid amount specified for TestV2ERC20Deposit")

r.ApproveERC20(r.GatewayEVMAddr)
r.ApproveERC20OnEVM(r.GatewayEVMAddr)

// perform the deposit
tx := r.V2ERC20Deposit(r.EVMAddress(), amount)
Expand Down
2 changes: 1 addition & 1 deletion e2e/e2etests/test_v2_erc20_deposit_and_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestV2ERC20DepositAndCall(r *runner.E2ERunner, args []string) {
amount, ok := big.NewInt(0).SetString(args[0], 10)
require.True(r, ok, "Invalid amount specified for TestV2ERC20DepositAndCall")

r.ApproveERC20(r.GatewayEVMAddr)
r.ApproveERC20OnEVM(r.GatewayEVMAddr)

r.AssertTestDAppValues(false, payloadMessageERC20, amount)

Expand Down
4 changes: 4 additions & 0 deletions e2e/e2etests/test_v2_eth_withdraw.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package e2etests

import (
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"
"math/big"

"github.com/stretchr/testify/require"
Expand All @@ -15,10 +16,13 @@ func TestV2ETHWithdraw(r *runner.E2ERunner, args []string) {
amount, ok := big.NewInt(0).SetString(args[0], 10)
require.True(r, ok, "Invalid amount specified for TestV2ETHWithdraw")

r.ApproveETHZRC20(r.GatewayZEVMAddr)

// perform the withdraw
tx := r.V2ETHWithdraw(r.EVMAddress(), amount)

// 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)
}
2 changes: 2 additions & 0 deletions e2e/e2etests/test_v2_eth_withdraw_and_call.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package e2etests

import (
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"
"math/big"

"github.com/stretchr/testify/require"
Expand All @@ -24,4 +25,5 @@ func TestV2ETHWithdrawAndCall(r *runner.E2ERunner, args []string) {
// 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)
}
2 changes: 2 additions & 0 deletions e2e/e2etests/test_v2_evm_to_zevm_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package e2etests

import (
"github.com/stretchr/testify/require"
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"

"github.com/zeta-chain/zetacore/e2e/runner"
"github.com/zeta-chain/zetacore/e2e/utils"
Expand All @@ -19,4 +20,5 @@ func TestV2EVMToZEVMCall(r *runner.E2ERunner, args []string) {
// 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)
}
2 changes: 2 additions & 0 deletions e2e/e2etests/test_v2_zevm_to_evm_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package e2etests

import (
"github.com/stretchr/testify/require"
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"

"github.com/zeta-chain/zetacore/e2e/runner"
"github.com/zeta-chain/zetacore/e2e/utils"
Expand All @@ -19,4 +20,5 @@ func TestV2ZEVMToEVMCall(r *runner.E2ERunner, args []string) {
// 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)
}
20 changes: 18 additions & 2 deletions e2e/runner/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,10 @@ func (r *E2ERunner) SendEther(_ ethcommon.Address, value *big.Int, data []byte)
return signedTx, nil
}

// ApproveERC20 approves ERC20 on EVM to a specific address
// ApproveERC20OnEVM approves ERC20 on EVM to a specific address
// check if allowance is zero before calling this method
// allow a high amount to avoid multiple approvals
func (r *E2ERunner) ApproveERC20(allowed ethcommon.Address) {
func (r *E2ERunner) ApproveERC20OnEVM(allowed ethcommon.Address) {
allowance, err := r.ERC20.Allowance(&bind.CallOpts{}, r.Account.EVMAddress(), r.GatewayEVMAddr)
require.NoError(r, err)

Expand All @@ -181,6 +181,22 @@ func (r *E2ERunner) ApproveERC20(allowed ethcommon.Address) {
}
}

// ApproveETHZRC20 approves ETH ZRC20 on EVM to a specific address
// check if allowance is zero before calling this method
// allow a high amount to avoid multiple approvals
func (r *E2ERunner) ApproveETHZRC20(allowed ethcommon.Address) {
allowance, err := r.ETHZRC20.Allowance(&bind.CallOpts{}, r.Account.EVMAddress(), r.GatewayEVMAddr)
require.NoError(r, err)

// approve 1M*1e18 if allowance is zero
if allowance.Cmp(big.NewInt(0)) == 0 {
tx, err := r.ETHZRC20.Approve(r.ZEVMAuth, allowed, big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1000000)))
require.NoError(r, err)
receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout)
require.True(r, receipt.Status == 1, "approval failed")
}
}

// AnvilMineBlocks mines blocks on Anvil localnet
// the block time is provided in seconds
// the method returns a function to stop the mining
Expand Down
1 change: 1 addition & 0 deletions e2e/runner/v2_setup_zeta.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func (r *E2ERunner) SetZEVMContractsV2() {
require.NoError(r, err)

// Deploy the proxy contract
r.Logger.Info("Deploying proxy with %s and %s, address: %s", r.WZetaAddr.Hex(), r.Account.EVMAddress().Hex(), gatewayZEVMAddr.Hex())
proxyAddress, txProxy, _, err := erc1967proxy.DeployERC1967Proxy(
r.ZEVMAuth,
r.ZEVMClient,
Expand Down
3 changes: 2 additions & 1 deletion x/crosschain/keeper/v2_zevm_inbound.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
"encoding/hex"
"fmt"

errorsmod "cosmossdk.io/errors"
Expand Down Expand Up @@ -133,7 +134,7 @@ func (k Keeper) newWithdrawalInbound(
toAddr,
foreignCoin.ForeignChainId,
math.NewUintFromBigInt(event.Value),
"",
hex.EncodeToString(event.Message),
event.Raw.TxHash.String(),
event.Raw.BlockNumber,
gasLimit.Uint64(),
Expand Down
6 changes: 3 additions & 3 deletions zetaclient/chains/bitcoin/signer/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func (signer *Signer) SignWithdrawTx(
signer.Logger().
Std.Error().
Err(err).
Msgf("SignWithdrawTx: FetchUTXOs error: nonce %d chain %d", nonce, chain.ChainId)
Msgf("SignGasWithdraw: FetchUTXOs error: nonce %d chain %d", nonce, chain.ChainId)
}

// select N UTXOs to cover the total expense
Expand Down Expand Up @@ -416,7 +416,7 @@ func (signer *Signer) TryProcessOutbound(
true, chain.ChainId, cctx.Index, cctx.InboundParams.Sender, params.Receiver, "BTC")
amount = 0.0 // zero out the amount to cancel the tx
}
logger.Info().Msgf("SignWithdrawTx: to %s, value %d sats", to.EncodeAddress(), params.Amount.Uint64())
logger.Info().Msgf("SignGasWithdraw: to %s, value %d sats", to.EncodeAddress(), params.Amount.Uint64())

// sign withdraw tx
tx, err := signer.SignWithdrawTx(
Expand All @@ -432,7 +432,7 @@ func (signer *Signer) TryProcessOutbound(
cancelTx,
)
if err != nil {
logger.Warn().Err(err).Msgf("SignOutbound error: nonce %d chain %d", outboundTssNonce, params.ReceiverChainId)
logger.Warn().Err(err).Msgf("SignConnectorOnReceive error: nonce %d chain %d", outboundTssNonce, params.ReceiverChainId)
return
}
logger.Info().
Expand Down
63 changes: 63 additions & 0 deletions zetaclient/chains/evm/cctx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package evm

import (
"github.com/zeta-chain/zetacore/pkg/coin"
"github.com/zeta-chain/zetacore/x/crosschain/types"
)

// OutboundTypes enumerate the different types of outbound transactions
// NOTE: only used for v2 protocol contracts and currently excludes ZETA withdraws
type OutboundTypes int

const (
// OutboundTypeUnknown is an unknown outbound transaction
OutboundTypeUnknown OutboundTypes = iota

// OutboundTypeGasWithdraw is a gas withdraw transaction
OutboundTypeGasWithdraw

// OutboundTypeERC20Withdraw is an ERC20 withdraw transaction
OutboundTypeERC20Withdraw

// OutboundTypeGasWithdrawAndCall is a gas withdraw and call transaction
OutboundTypeGasWithdrawAndCall

// OutboundTypeERC20WithdrawAndCall is an ERC20 withdraw and call transaction
OutboundTypeERC20WithdrawAndCall

// OutboundTypeCall is a no-asset call transaction
OutboundTypeCall

// OutboundTypeGasWithdrawAndRevert is a gas withdraw and revert call
OutboundTypeGasWithdrawAndRevert

// OutboundTypeERC20WithdrawAndRevert is an ERC20 withdraw and revert call
OutboundTypeERC20WithdrawAndRevert
)

// ParseOutboundTypeFromCCTX returns the outbound type from the CCTX
// TODO: address revert
func ParseOutboundTypeFromCCTX(cctx types.CrossChainTx) OutboundTypes {
switch cctx.InboundParams.CoinType {
case coin.CoinType_Gas:
switch cctx.CctxStatus.Status {
case types.CctxStatus_PendingOutbound:
if len(cctx.RelayedMessage) == 0 {
return OutboundTypeGasWithdraw
} else {
return OutboundTypeGasWithdrawAndCall
}
}
case coin.CoinType_ERC20:
switch cctx.CctxStatus.Status {
case types.CctxStatus_PendingOutbound:
if len(cctx.RelayedMessage) == 0 {
return OutboundTypeERC20Withdraw
} else {
return OutboundTypeERC20WithdrawAndCall
}
}
}

return OutboundTypeUnknown
}
110 changes: 57 additions & 53 deletions zetaclient/chains/evm/observer/outbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,63 @@ func (ob *Observer) VoteOutboundIfConfirmed(
return false, nil
}

// ParseOutboundReceivedValue parses the received value and status from the outbound receipt
// The receivd value is the amount of Zeta/ERC20/Gas token (released from connector/custody/TSS) sent to the receiver
func ParseOutboundReceivedValue(
cctx *crosschaintypes.CrossChainTx,
receipt *ethtypes.Receipt,
transaction *ethtypes.Transaction,
cointype coin.CoinType,
connectorAddress ethcommon.Address,
connector *zetaconnector.ZetaConnectorNonEth,
custodyAddress ethcommon.Address,
custody *erc20custody.ERC20Custody,
) (*big.Int, chains.ReceiveStatus, error) {
// determine the receive status and value
// https://docs.nethereum.com/en/latest/nethereum-receipt-status/
receiveValue := big.NewInt(0)
receiveStatus := chains.ReceiveStatus_failed
if receipt.Status == ethtypes.ReceiptStatusSuccessful {
receiveValue = transaction.Value()
receiveStatus = chains.ReceiveStatus_success
}

if cctx.ProtocolContractVersion == crosschaintypes.ProtocolContractVersion_V2 {
return ParseOutboundEventV2(cctx, receipt, transaction)
}

// parse receive value from the outbound receipt for Zeta and ERC20
switch cointype {
case coin.CoinType_Zeta:
if receipt.Status == ethtypes.ReceiptStatusSuccessful {
receivedLog, revertedLog, err := ParseAndCheckZetaEvent(cctx, receipt, connectorAddress, connector)
if err != nil {
return nil, chains.ReceiveStatus_failed, err
}
// use the value in ZetaReceived/ZetaReverted event for vote message
if receivedLog != nil {
receiveValue = receivedLog.ZetaValue
} else if revertedLog != nil {
receiveValue = revertedLog.RemainingZetaValue
}
}
case coin.CoinType_ERC20:
if receipt.Status == ethtypes.ReceiptStatusSuccessful {
withdrawn, err := ParseAndCheckWithdrawnEvent(cctx, receipt, custodyAddress, custody)
if err != nil {
return nil, chains.ReceiveStatus_failed, err
}
// use the value in Withdrawn event for vote message
receiveValue = withdrawn.Amount
}
case coin.CoinType_Gas, coin.CoinType_Cmd:
// nothing to do for CoinType_Gas/CoinType_Cmd, no need to parse event
default:
return nil, chains.ReceiveStatus_failed, fmt.Errorf("unknown coin type %s", cointype)
}
return receiveValue, receiveStatus, nil
}

// ParseAndCheckZetaEvent parses and checks ZetaReceived/ZetaReverted event from the outbound receipt
// It either returns an ZetaReceived or an ZetaReverted event, or an error if no event found
func ParseAndCheckZetaEvent(
Expand Down Expand Up @@ -314,59 +371,6 @@ func ParseAndCheckWithdrawnEvent(
return nil, errors.New("no ERC20 Withdrawn event found")
}

// ParseOutboundReceivedValue parses the received value and status from the outbound receipt
// The receivd value is the amount of Zeta/ERC20/Gas token (released from connector/custody/TSS) sent to the receiver
func ParseOutboundReceivedValue(
cctx *crosschaintypes.CrossChainTx,
receipt *ethtypes.Receipt,
transaction *ethtypes.Transaction,
cointype coin.CoinType,
connectorAddress ethcommon.Address,
connector *zetaconnector.ZetaConnectorNonEth,
custodyAddress ethcommon.Address,
custody *erc20custody.ERC20Custody,
) (*big.Int, chains.ReceiveStatus, error) {
// determine the receive status and value
// https://docs.nethereum.com/en/latest/nethereum-receipt-status/
receiveValue := big.NewInt(0)
receiveStatus := chains.ReceiveStatus_failed
if receipt.Status == ethtypes.ReceiptStatusSuccessful {
receiveValue = transaction.Value()
receiveStatus = chains.ReceiveStatus_success
}

// parse receive value from the outbound receipt for Zeta and ERC20
switch cointype {
case coin.CoinType_Zeta:
if receipt.Status == ethtypes.ReceiptStatusSuccessful {
receivedLog, revertedLog, err := ParseAndCheckZetaEvent(cctx, receipt, connectorAddress, connector)
if err != nil {
return nil, chains.ReceiveStatus_failed, err
}
// use the value in ZetaReceived/ZetaReverted event for vote message
if receivedLog != nil {
receiveValue = receivedLog.ZetaValue
} else if revertedLog != nil {
receiveValue = revertedLog.RemainingZetaValue
}
}
case coin.CoinType_ERC20:
if receipt.Status == ethtypes.ReceiptStatusSuccessful {
withdrawn, err := ParseAndCheckWithdrawnEvent(cctx, receipt, custodyAddress, custody)
if err != nil {
return nil, chains.ReceiveStatus_failed, err
}
// use the value in Withdrawn event for vote message
receiveValue = withdrawn.Amount
}
case coin.CoinType_Gas, coin.CoinType_Cmd:
// nothing to do for CoinType_Gas/CoinType_Cmd, no need to parse event
default:
return nil, chains.ReceiveStatus_failed, fmt.Errorf("unknown coin type %s", cointype)
}
return receiveValue, receiveStatus, nil
}

// checkConfirmedTx checks if a txHash is confirmed
// returns (receipt, transaction, true) if confirmed or (nil, nil, false) otherwise
func (ob *Observer) checkConfirmedTx(
Expand Down
Loading

0 comments on commit 99cdcf5

Please sign in to comment.