Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
### Tests

* [3692](https://github.com/zeta-chain/node/pull/3692) - e2e staking test for `MsgUndelegate` tx, to test observer staking hooks
* [3831](https://github.com/zeta-chain/node/pull/3831) - e2e tests for sui fungible token withdraw and call

### Refactor

Expand Down
7 changes: 4 additions & 3 deletions cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,11 +521,12 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
e2etests.TestSuiTokenDepositAndCallName,
e2etests.TestSuiTokenDepositAndCallRevertName,
e2etests.TestSuiWithdrawName,
e2etests.TestSuiWithdrawRevertWithCallName,
e2etests.TestSuiTokenWithdrawName,
// https://github.com/zeta-chain/node/issues/3742
e2etests.TestSuiWithdrawAndCallName,
e2etests.TestSuiWithdrawRevertWithCallName,
e2etests.TestSuiWithdrawAndCallRevertWithCallName,
e2etests.TestSuiTokenWithdrawName,
e2etests.TestSuiTokenWithdrawAndCallName,
e2etests.TestSuiTokenWithdrawAndCallRevertWithCallName,
e2etests.TestSuiDepositRestrictedName,
e2etests.TestSuiWithdrawRestrictedName,
}
Expand Down
1 change: 0 additions & 1 deletion e2e/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ type SuiExample struct {
GlobalConfigID DoubleQuotedString `yaml:"global_config_id"`
PartnerID DoubleQuotedString `yaml:"partner_id"`
ClockID DoubleQuotedString `yaml:"clock_id"`
PoolID DoubleQuotedString `yaml:"pool_id"`
}

// Sui contains the addresses of predeployed contracts on the Sui chain
Expand Down
Binary file modified e2e/contracts/sui/connected.mv
Binary file not shown.
4 changes: 2 additions & 2 deletions e2e/contracts/sui/example/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ clean:
# Build the package and generate bytecode
build:
sui move build
cp build/example/bytecode_modules/token.mv .
cp build/example/bytecode_modules/connected.mv .
cp build/example/bytecode_modules/token.mv ../token.mv
cp build/example/bytecode_modules/connected.mv ../connected.mv

# Help target
help:
Expand Down
24 changes: 7 additions & 17 deletions e2e/contracts/sui/example/Move.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,47 @@

[move]
version = 3
manifest_digest = "795BC4DE1AC42C1015B85547951A89D7F9AD63EA50982960E095E815C560BFCC"
deps_digest = "397E6A9F7A624706DBDFEE056CE88391A15876868FD18A88504DA74EB458D697"
manifest_digest = "9AE1AA02EF00BB882BBF7AA642D0DDF8A788CB1C25ACA9667399B8001C02CF81"
deps_digest = "F9B494B64F0615AED0E98FC12A85B85ECD2BC5185C22D30E7F67786BB52E507C"
dependencies = [
{ id = "Bridge", name = "Bridge" },
{ id = "DeepBook", name = "DeepBook" },
{ id = "MoveStdlib", name = "MoveStdlib" },
{ id = "Sui", name = "Sui" },
{ id = "SuiSystem", name = "SuiSystem" },
]

[[move.package]]
id = "Bridge"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "9c04e1840eb5", subdir = "crates/sui-framework/packages/bridge" }
source = { git = "https://github.com/MystenLabs/sui.git", rev = "fbb68879cbd1", subdir = "crates/sui-framework/packages/bridge" }

dependencies = [
{ id = "MoveStdlib", name = "MoveStdlib" },
{ id = "Sui", name = "Sui" },
{ id = "SuiSystem", name = "SuiSystem" },
]

[[move.package]]
id = "DeepBook"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "9c04e1840eb5", subdir = "crates/sui-framework/packages/deepbook" }

dependencies = [
{ id = "MoveStdlib", name = "MoveStdlib" },
{ id = "Sui", name = "Sui" },
]

[[move.package]]
id = "MoveStdlib"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "9c04e1840eb5", subdir = "crates/sui-framework/packages/move-stdlib" }
source = { git = "https://github.com/MystenLabs/sui.git", rev = "fbb68879cbd1", subdir = "crates/sui-framework/packages/move-stdlib" }

[[move.package]]
id = "Sui"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "9c04e1840eb5", subdir = "crates/sui-framework/packages/sui-framework" }
source = { git = "https://github.com/MystenLabs/sui.git", rev = "fbb68879cbd1", subdir = "crates/sui-framework/packages/sui-framework" }

dependencies = [
{ id = "MoveStdlib", name = "MoveStdlib" },
]

[[move.package]]
id = "SuiSystem"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "9c04e1840eb5", subdir = "crates/sui-framework/packages/sui-system" }
source = { git = "https://github.com/MystenLabs/sui.git", rev = "fbb68879cbd1", subdir = "crates/sui-framework/packages/sui-system" }

dependencies = [
{ id = "MoveStdlib", name = "MoveStdlib" },
{ id = "Sui", name = "Sui" },
]

[move.toolchain-version]
compiler-version = "1.45.0"
compiler-version = "1.47.0"
edition = "2024.beta"
flavor = "sui"
Binary file removed e2e/contracts/sui/example/connected.mv
Binary file not shown.
7 changes: 5 additions & 2 deletions e2e/contracts/sui/example/sources/example.move
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ fun init(ctx: &mut TxContext) {
transfer::share_object(clock);
}

public entry fun on_call<SOURCE_COIN, TARGET_COIN>(
public entry fun on_call<SOURCE_COIN>(
in_coins: Coin<SOURCE_COIN>,
cetus_config: &mut GlobalConfig,
_pool: &mut Pool<SOURCE_COIN, TARGET_COIN>,
// Note: this pool type is hardcoded as <SUI, TOKEN> and therefore causes type mismatch error in the
// fungible token withdrawAndCall test, where the SOURCE_COIN type is FAKE_USDC instead of TOKEN.
// Disabling the pool object for now is the easiest solution to allow the E2E tests to go through.
// _pool: &mut Pool<SOURCE_COIN, TARGET_COIN>,
_cetus_partner: &mut Partner,
_clock: &Clock,
data: vector<u8>,
Expand Down
Binary file removed e2e/contracts/sui/example/token.mv
Binary file not shown.
46 changes: 33 additions & 13 deletions e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,21 @@ const (
/*
Sui tests
*/
TestSuiDepositName = "sui_deposit"
TestSuiDepositAndCallName = "sui_deposit_and_call"
TestSuiDepositAndCallRevertName = "sui_deposit_and_call_revert"
TestSuiTokenDepositName = "sui_token_deposit" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiTokenDepositAndCallName = "sui_token_deposit_and_call" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiTokenDepositAndCallRevertName = "sui_token_deposit_and_call_revert" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiWithdrawName = "sui_withdraw"
TestSuiTokenWithdrawName = "sui_token_withdraw" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiWithdrawAndCallName = "sui_withdraw_and_call"
TestSuiWithdrawRevertWithCallName = "sui_withdraw_revert_with_call" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiWithdrawAndCallRevertWithCallName = "sui_withdraw_and_call_revert_with_call" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiDepositRestrictedName = "sui_deposit_restricted"
TestSuiWithdrawRestrictedName = "sui_withdraw_restricted"
TestSuiDepositName = "sui_deposit"
TestSuiDepositAndCallName = "sui_deposit_and_call"
TestSuiDepositAndCallRevertName = "sui_deposit_and_call_revert"
TestSuiTokenDepositName = "sui_token_deposit" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiTokenDepositAndCallName = "sui_token_deposit_and_call" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiTokenDepositAndCallRevertName = "sui_token_deposit_and_call_revert" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiWithdrawName = "sui_withdraw"
TestSuiTokenWithdrawName = "sui_token_withdraw" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiTokenWithdrawAndCallName = "sui_token_withdraw_and_call" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiTokenWithdrawAndCallRevertWithCallName = "sui_token_withdraw_and_call_revert_with_call" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiWithdrawAndCallName = "sui_withdraw_and_call"
TestSuiWithdrawRevertWithCallName = "sui_withdraw_revert_with_call" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiWithdrawAndCallRevertWithCallName = "sui_withdraw_and_call_revert_with_call" // #nosec G101: Potential hardcoded credentials (gosec), not a credential
TestSuiDepositRestrictedName = "sui_deposit_restricted"
TestSuiWithdrawRestrictedName = "sui_withdraw_restricted"

/*
Bitcoin tests
Expand Down Expand Up @@ -902,6 +904,24 @@ var AllE2ETests = []runner.E2ETest{
TestSuiTokenWithdraw,
runner.WithMinimumVersion("v29.0.0"),
),
runner.NewE2ETest(
TestSuiTokenWithdrawAndCallName,
"withdraw fungible token from ZEVM and call a contract",
[]runner.ArgDefinition{
{Description: "amount in base unit", DefaultValue: "100000"},
},
TestSuiTokenWithdrawAndCall,
runner.WithMinimumVersion("v30.0.0"),
),
runner.NewE2ETest(
TestSuiTokenWithdrawAndCallRevertWithCallName,
"withdraw fungible token from ZEVM and call a contract that reverts with a onRevert call",
[]runner.ArgDefinition{
{Description: "amount in base unit", DefaultValue: "1000000"},
},
TestSuiTokenWithdrawAndCallRevertWithCall,
runner.WithMinimumVersion("v30.0.0"),
),
runner.NewE2ETest(
TestSuiDepositRestrictedName,
"deposit SUI into ZEVM restricted address",
Expand Down
62 changes: 62 additions & 0 deletions e2e/e2etests/test_sui_token_withdraw_and_call.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package e2etests

import (
"math/big"

"github.com/stretchr/testify/require"
"github.com/zeta-chain/protocol-contracts/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"
)

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

// ARRANGE
// Given target package ID (example package) and a token amount
targetPackageID := r.SuiExample.PackageID.String()
amount := utils.ParseBigInt(r, args[0])

// use the deployer address as on_call payload message
signer, err := r.Account.SuiSigner()
require.NoError(r, err, "get deployer signer")
suiAddress := signer.Address()

// Given initial balance and called_count
balanceBefore := r.SuiGetFungibleTokenBalance(suiAddress)
calledCountBefore := r.SuiGetConnectedCalledCount()

// create the on_call payload
payloadOnCall, err := r.SuiCreateExampleWACPayload(suiAddress)
require.NoError(r, err)

// ACT
// approve both SUI gas budget token and fungible token ZRC20
r.ApproveSUIZRC20(r.GatewayZEVMAddr)
r.ApproveFungibleTokenZRC20(r.GatewayZEVMAddr)

// perform the fungible token withdraw and call
tx := r.SuiWithdrawAndCallFungibleToken(
targetPackageID,
amount,
payloadOnCall,
gatewayzevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)},
)
r.Logger.EVMTransaction(*tx, "withdraw_and_call")

// ASSERT
// 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.EqualValues(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status)

// check the balance after the withdraw
balanceAfter := r.SuiGetFungibleTokenBalance(signer.Address())
require.EqualValues(r, balanceBefore+amount.Uint64(), balanceAfter)

// verify the called_count increased by 1
calledCountAfter := r.SuiGetConnectedCalledCount()
require.Equal(r, calledCountBefore+1, calledCountAfter)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package e2etests

import (
"math/big"

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

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

// TestSuiTokenWithdrawAndCallRevertWithCall executes withdrawAndCall on zevm gateway with fungible token.
// The outbound is rejected by the connected module due to invalid payload (invalid address),
// and 'onRevert' is called instead to handle the revert.
func TestSuiTokenWithdrawAndCallRevertWithCall(r *runner.E2ERunner, args []string) {
require.Len(r, args, 1)

// ARRANGE
// Given target package ID (example package) and a token amount
targetPackageID := r.SuiExample.PackageID.String()
amount := utils.ParseBigInt(r, args[0])

// create the payload for 'on_call' with invalid address
// taking the first 10 letters to form an invalid address
invalidAddress := sample.SuiAddress(r)[:10]
payloadOnCall, err := r.SuiCreateExampleWACPayload(invalidAddress)
require.NoError(r, err)

// given ZEVM revert address (the dApp)
dAppAddress := r.TestDAppV2ZEVMAddr
dAppBalanceBefore, err := r.SuiTokenZRC20.BalanceOf(&bind.CallOpts{}, dAppAddress)
require.NoError(r, err)

// given random payload for 'onRevert'
payloadOnRevert := randomPayload(r)
r.AssertTestDAppEVMCalled(false, payloadOnRevert, amount)

// ACT
// approve both SUI gas budget token and fungible token ZRC20
r.ApproveSUIZRC20(r.GatewayZEVMAddr)
r.ApproveFungibleTokenZRC20(r.GatewayZEVMAddr)

// perform the withdraw and call with revert options
tx := r.SuiWithdrawAndCallFungibleToken(
targetPackageID,
amount,
payloadOnCall,
gatewayzevm.RevertOptions{
CallOnRevert: true,
RevertAddress: dAppAddress,
RevertMessage: []byte(payloadOnRevert),
OnRevertGasLimit: big.NewInt(0),
},
)
r.Logger.EVMTransaction(*tx, "withdraw_and_call")

// ASSERT
// wait for the cctx to be reverted
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "withdraw")
utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_Reverted)

// should have called 'onRevert'
r.AssertTestDAppZEVMCalled(true, payloadOnRevert, big.NewInt(0))

// sender and message should match
sender, err := r.TestDAppV2ZEVM.SenderWithMessage(
&bind.CallOpts{},
[]byte(payloadOnRevert),
)
require.NoError(r, err)
require.Equal(r, r.ZEVMAuth.From, sender)

// the dApp address should get reverted amount
dAppBalanceAfter, err := r.SuiTokenZRC20.BalanceOf(&bind.CallOpts{}, dAppAddress)
require.NoError(r, err)
require.Equal(r, amount.Int64(), dAppBalanceAfter.Int64()-dAppBalanceBefore.Int64())
}
31 changes: 9 additions & 22 deletions e2e/e2etests/test_sui_withdraw_and_call.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package e2etests

import (
"encoding/hex"
"math/big"

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

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

Expand All @@ -21,29 +19,18 @@ func TestSuiWithdrawAndCall(r *runner.E2ERunner, args []string) {
targetPackageID := r.SuiExample.PackageID.String()
amount := utils.ParseBigInt(r, args[0])

// Given example contract on_call function arguments
argumentTypes := []string{
r.SuiExample.TokenType.String(),
}
objects := []string{
r.SuiExample.GlobalConfigID.String(),
r.SuiExample.PoolID.String(),
r.SuiExample.PartnerID.String(),
r.SuiExample.ClockID.String(),
}
// use the deployer address as on_call payload message
signer, err := r.Account.SuiSigner()
require.NoError(r, err, "get deployer signer")
suiAddress := signer.Address()

// define a deterministic address and use it for on_call payload message
// the example contract will just forward the withdrawn SUI token to this address
suiAddress := "0x34a30aaee833d649d7313ddfe4ff5b6a9bac48803236b919369e6636fe93392e"
message, err := hex.DecodeString(suiAddress[2:]) // remove 0x prefix
require.NoError(r, err)
// Given initial balance and called_count
balanceBefore := r.SuiGetSUIBalance(suiAddress)

// query the called_count before withdraw and call
calledCountBefore := r.SuiGetConnectedCalledCount()

// create the payload
payload := sui.NewCallPayload(argumentTypes, objects, message)
// create the on_call payload
payloadOnCall, err := r.SuiCreateExampleWACPayload(suiAddress)
require.NoError(r, err)

// ACT
// approve SUI ZRC20 token
Expand All @@ -53,7 +40,7 @@ func TestSuiWithdrawAndCall(r *runner.E2ERunner, args []string) {
tx := r.SuiWithdrawAndCallSUI(
targetPackageID,
amount,
payload,
payloadOnCall,
gatewayzevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)},
)
r.Logger.EVMTransaction(*tx, "withdraw_and_call")
Expand Down
Loading