From 8bca1be154266671f684c8fea4e81ce184a566a2 Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:48:16 +0100 Subject: [PATCH 01/12] refactor ton e2e client & deployer --- e2e/runner/ton/accounts.go | 25 +++++- e2e/runner/ton/accounts_test.go | 8 +- e2e/runner/ton/client.go | 110 ++++++++++++++++++++++++++ e2e/runner/ton/clients.go | 132 -------------------------------- e2e/runner/ton/deployer.go | 116 ++++------------------------ e2e/runner/ton/faucet.go | 53 +++++++++++++ 6 files changed, 205 insertions(+), 239 deletions(-) create mode 100644 e2e/runner/ton/client.go delete mode 100644 e2e/runner/ton/clients.go create mode 100644 e2e/runner/ton/faucet.go diff --git a/e2e/runner/ton/accounts.go b/e2e/runner/ton/accounts.go index bed0ba7c21..8c317ef850 100644 --- a/e2e/runner/ton/accounts.go +++ b/e2e/runner/ton/accounts.go @@ -1,7 +1,9 @@ package ton import ( + "encoding/hex" "fmt" + "strings" eth "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" @@ -23,18 +25,35 @@ type AccountInit struct { ID ton.AccountID } +func PrivateKeyFromHex(raw string) (ed25519.PrivateKey, error) { + b, err := hex.DecodeString(strings.TrimPrefix(raw, "0x")) + if err != nil { + return nil, errors.Wrap(err, "failed to decode private key") + } + + if len(b) != ed25519.SeedSize { + return nil, errors.New("invalid private key length") + } + + return ed25519.NewKeyFromSeed(b), nil +} + // ConstructWalletFromSeed constructs wallet AccountInit from seed. // Used for wallets deployment. -func ConstructWalletFromSeed(seed string, client blockchain) (*AccountInit, *wallet.Wallet, error) { +func ConstructWalletFromSeed(seed string, client *Client) (*AccountInit, *wallet.Wallet, error) { + if seed == "" { + return nil, nil, errors.New("seed is empty") + } + pk, err := wallet.SeedToPrivateKey(seed) if err != nil { - return nil, nil, errors.Wrap(err, "invalid mnemonic") + return nil, nil, errors.Wrapf(err, "invalid mnemonic") } return ConstructWalletFromPrivateKey(pk, client) } -func ConstructWalletFromPrivateKey(pk ed25519.PrivateKey, client blockchain) (*AccountInit, *wallet.Wallet, error) { +func ConstructWalletFromPrivateKey(pk ed25519.PrivateKey, client *Client) (*AccountInit, *wallet.Wallet, error) { const version = wallet.V5R1 w, err := wallet.New(pk, version, client) diff --git a/e2e/runner/ton/accounts_test.go b/e2e/runner/ton/accounts_test.go index df1668c3af..cce9153109 100644 --- a/e2e/runner/ton/accounts_test.go +++ b/e2e/runner/ton/accounts_test.go @@ -1,6 +1,7 @@ package ton import ( + "encoding/hex" "testing" "github.com/stretchr/testify/require" @@ -11,8 +12,13 @@ func TestWalletConstruction(t *testing.T) { // ARRANGE seed := wallet.RandomSeed() + pk, err := wallet.SeedToPrivateKey(seed) + require.NoError(t, err) + + t.Logf("seed[ %s ] ==> privateKey(0x%s)", seed, hex.EncodeToString(pk.Seed())) + // ACT - accInit, w, err := ConstructWalletFromSeed(seed, nil) + accInit, w, err := ConstructWalletFromPrivateKey(pk, nil) // ASSERT require.NoError(t, err) diff --git a/e2e/runner/ton/client.go b/e2e/runner/ton/client.go new file mode 100644 index 0000000000..187880fdd4 --- /dev/null +++ b/e2e/runner/ton/client.go @@ -0,0 +1,110 @@ +package ton + +import ( + "context" + "fmt" + "time" + + "cosmossdk.io/math" + "github.com/pkg/errors" + "github.com/tonkeeper/tongo/liteapi" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" +) + +type Client struct { + *liteapi.Client +} + +// Status checks the health of the TON node +func (c *Client) Status(ctx context.Context) error { + _, err := c.GetMasterchainInfo(ctx) + return err +} + +// GetBalanceOf returns the balance of a given account. +// wait=true waits for account activation. +func (c *Client) GetBalanceOf(ctx context.Context, id ton.AccountID, wait bool) (math.Uint, error) { + if wait { + if err := c.WaitForAccountActivation(ctx, id); err != nil { + return math.Uint{}, errors.Wrap(err, "failed to wait for account activation") + } + } + + state, err := c.GetAccountState(ctx, id) + if err != nil { + return math.Uint{}, errors.Wrapf(err, "failed to get account %s state", id.ToRaw()) + } + + balance := uint64(state.Account.Account.Storage.Balance.Grams) + + return math.NewUint(balance), nil +} + +func (c *Client) WaitForBlocks(ctx context.Context) error { + const ( + blocksToWait = 3 + interval = 3 * time.Second + ) + + block, err := c.GetMasterchainInfo(ctx) + if err != nil { + return err + } + + waitFor := block.Last.Seqno + blocksToWait + + for { + freshBlock, err := c.GetMasterchainInfo(ctx) + if err != nil { + return err + } + + if waitFor < freshBlock.Last.Seqno { + return nil + } + + time.Sleep(interval) + } +} + +func (c *Client) WaitForAccountActivation(ctx context.Context, account ton.AccountID) error { + const interval = 5 * time.Second + + for i := 0; i < 10; i++ { + state, err := c.GetAccountState(ctx, account) + if err != nil { + return err + } + + if state.Account.Status() == tlb.AccountActive { + return nil + } + + time.Sleep(interval) + } + + return fmt.Errorf("account %q is not active; timed out", account.ToRaw()) +} + +func (c *Client) WaitForNextSeqno( + ctx context.Context, + id ton.AccountID, + oldSeqno uint32, + timeout time.Duration, +) error { + t := time.Now() + + for ; time.Since(t) < timeout; time.Sleep(timeout / 10) { + newSeqno, err := c.GetSeqno(ctx, id) + if err != nil { + return errors.Wrap(err, "failed to get seqno") + } + + if newSeqno > oldSeqno { + return nil + } + } + + return errors.New("waiting confirmation timeout") +} diff --git a/e2e/runner/ton/clients.go b/e2e/runner/ton/clients.go deleted file mode 100644 index d24e0a492e..0000000000 --- a/e2e/runner/ton/clients.go +++ /dev/null @@ -1,132 +0,0 @@ -package ton - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "time" - - "github.com/pkg/errors" - ton "github.com/tonkeeper/tongo/liteapi" -) - -type Client struct { - *ton.Client - *SidecarClient -} - -func (c *Client) WaitForBlocks(ctx context.Context) error { - const ( - blocksToWait = 3 - interval = 3 * time.Second - ) - - block, err := c.GetMasterchainInfo(ctx) - if err != nil { - return err - } - - waitFor := block.Last.Seqno + blocksToWait - - for { - freshBlock, err := c.GetMasterchainInfo(ctx) - if err != nil { - return err - } - - if waitFor < freshBlock.Last.Seqno { - return nil - } - - time.Sleep(interval) - } -} - -type SidecarClient struct { - baseURL string - c *http.Client -} - -var ErrNotHealthy = fmt.Errorf("TON node is not healthy yet") - -func NewSidecarClient(baseURL string) *SidecarClient { - c := &http.Client{Timeout: 3 * time.Second} - return &SidecarClient{baseURL, c} -} - -// Faucet represents the faucet information. -// -//nolint:revive,stylecheck // comes from my-local-ton -type Faucet struct { - InitialBalance int64 `json:"initialBalance"` - PrivateKey string `json:"privateKey"` - PublicKey string `json:"publicKey"` - WalletRawAddress string `json:"walletRawAddress"` - Mnemonic string `json:"mnemonic"` - WalletVersion string `json:"walletVersion"` - WorkChain int32 `json:"workChain"` - SubWalletId int `json:"subWalletId"` - Created bool `json:"created"` -} - -// LiteServerURL returns the URL to the lite server config -func (c *SidecarClient) LiteServerURL() string { - return fmt.Sprintf("%s/lite-client.json", c.baseURL) -} - -// GetFaucet returns the faucet information. -func (c *SidecarClient) GetFaucet(ctx context.Context) (Faucet, error) { - resp, err := c.get(ctx, "faucet.json") - if err != nil { - return Faucet{}, err - } - - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return Faucet{}, fmt.Errorf("unexpected response status: %d", resp.StatusCode) - } - - var faucet Faucet - if err := json.NewDecoder(resp.Body).Decode(&faucet); err != nil { - return Faucet{}, err - } - - return faucet, nil -} - -// Status checks the health of the TON node. Returns ErrNotHealthy or nil. -func (c *SidecarClient) Status(ctx context.Context) error { - resp, err := c.get(ctx, "status") - if err != nil { - return err - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("failed to read response body: %w", err) - } - - if err := resp.Body.Close(); err != nil { - return err - } - - if resp.StatusCode != http.StatusOK { - return errors.Wrapf(ErrNotHealthy, "status %d. %s", resp.StatusCode, string(body)) - } - - return nil -} - -func (c *SidecarClient) get(ctx context.Context, path string) (*http.Response, error) { - url := fmt.Sprintf("%s/%s", c.baseURL, path) - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) - if err != nil { - return nil, err - } - - return c.c.Do(req) -} diff --git a/e2e/runner/ton/deployer.go b/e2e/runner/ton/deployer.go index 3f12f784da..62b906e9ae 100644 --- a/e2e/runner/ton/deployer.go +++ b/e2e/runner/ton/deployer.go @@ -7,7 +7,6 @@ import ( "cosmossdk.io/math" "github.com/pkg/errors" - "github.com/tonkeeper/tongo/tlb" "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/wallet" @@ -17,18 +16,11 @@ import ( // Deployer represents a wrapper around ton Wallet with some helpful methods. type Deployer struct { wallet.Wallet - blockchain blockchain -} - -type blockchain interface { - GetSeqno(ctx context.Context, account ton.AccountID) (uint32, error) - SendMessage(ctx context.Context, payload []byte) (uint32, error) - GetAccountState(ctx context.Context, accountID ton.AccountID) (tlb.ShardAccount, error) - WaitForBlocks(ctx context.Context) error + client *Client } // NewDeployer deployer constructor. -func NewDeployer(client blockchain, cfg Faucet) (*Deployer, error) { +func NewDeployer(client *Client, cfg Faucet) (*Deployer, error) { // this is a bit outdated, but we can't change it (it's created by my-local-ton) const version = wallet.V3R2 if cfg.WalletVersion != "V3R2" { @@ -50,30 +42,7 @@ func NewDeployer(client blockchain, cfg Faucet) (*Deployer, error) { return nil, errors.Wrap(err, "failed to create wallet") } - return &Deployer{Wallet: w, blockchain: client}, nil -} - -func (d *Deployer) Seqno(ctx context.Context) (uint32, error) { - return d.blockchain.GetSeqno(ctx, d.GetAddress()) -} - -// GetBalanceOf returns the balance of a given account. -// wait=true waits for account activation. -func (d *Deployer) GetBalanceOf(ctx context.Context, id ton.AccountID, wait bool) (math.Uint, error) { - if wait { - if err := d.waitForAccountActivation(ctx, id); err != nil { - return math.Uint{}, errors.Wrap(err, "failed to wait for account activation") - } - } - - state, err := d.blockchain.GetAccountState(ctx, id) - if err != nil { - return math.Uint{}, errors.Wrapf(err, "failed to get account %s state", id.ToRaw()) - } - - balance := uint64(state.Account.Account.Storage.Balance.Grams) - - return math.NewUint(balance), nil + return &Deployer{Wallet: w, client: client}, nil } // Fund sends the given amount of coins to the recipient. Returns tx hash and error. @@ -93,100 +62,41 @@ func (d *Deployer) Deploy(ctx context.Context, account *AccountInit, amount math Address: account.ID, Code: account.Code, Data: account.Data, - Mode: 1, // pay gas fees separately + Mode: toncontracts.SendFlagSeparateFees, } if _, err := d.send(ctx, msg, true); err != nil { - return err + return errors.Wrapf(err, "unable to deploy account %q", account.ID.ToRaw()) } - return d.waitForAccountActivation(ctx, account.ID) -} - -func (d *Deployer) CreateWallet(ctx context.Context, amount math.Uint) (*wallet.Wallet, error) { - seed := wallet.RandomSeed() - - accInit, w, err := ConstructWalletFromSeed(seed, d.blockchain) - if err != nil { - return nil, errors.Wrap(err, "failed to construct wallet") - } - - if err := d.Deploy(ctx, accInit, amount); err != nil { - return nil, errors.Wrap(err, "failed to deploy wallet") - } - - // Double-check the balance - b, err := w.GetBalance(ctx) - if err != nil { - return nil, errors.Wrap(err, "failed to get balance") - } - - if b == 0 { - return nil, fmt.Errorf("balance of %s is zero", w.GetAddress().ToRaw()) - } - - return w, nil + return d.client.WaitForAccountActivation(ctx, account.ID) } func (d *Deployer) send(ctx context.Context, message wallet.Sendable, waitForBlocks bool) (ton.Bits256, error) { // 2-3 blocks const maxWaitingTime = 18 * time.Second - seqno, err := d.Seqno(ctx) + id := d.GetAddress() + + seqno, err := d.client.GetSeqno(ctx, id) if err != nil { return ton.Bits256{}, errors.Wrap(err, "failed to get seqno") } - // Note that message hash IS NOT a tra hash. - // It's not possible to get TX hash after tx sending + // Note that message hash IS NOT a tx hash. + // It's not possible to get tx hash right after tx sending msgHash, err := d.Wallet.SendV2(ctx, 0, message) if err != nil { return msgHash, errors.Wrap(err, "failed to send message") } - if err := d.waitForNextSeqno(ctx, seqno, maxWaitingTime); err != nil { + if err := d.client.WaitForNextSeqno(ctx, id, seqno, maxWaitingTime); err != nil { return msgHash, errors.Wrap(err, "failed to wait for confirmation") } if waitForBlocks { - return msgHash, d.blockchain.WaitForBlocks(ctx) + return msgHash, d.client.WaitForBlocks(ctx) } return msgHash, nil } - -func (d *Deployer) waitForNextSeqno(ctx context.Context, oldSeqno uint32, timeout time.Duration) error { - t := time.Now() - - for ; time.Since(t) < timeout; time.Sleep(timeout / 10) { - newSeqno, err := d.Seqno(ctx) - if err != nil { - return errors.Wrap(err, "failed to get seqno") - } - - if newSeqno > oldSeqno { - return nil - } - } - - return errors.New("waiting confirmation timeout") -} - -func (d *Deployer) waitForAccountActivation(ctx context.Context, account ton.AccountID) error { - const interval = 5 * time.Second - - for i := 0; i < 10; i++ { - state, err := d.blockchain.GetAccountState(ctx, account) - if err != nil { - return err - } - - if state.Account.Status() == tlb.AccountActive { - return nil - } - - time.Sleep(interval) - } - - return fmt.Errorf("account %s is not active", account.ToRaw()) -} diff --git a/e2e/runner/ton/faucet.go b/e2e/runner/ton/faucet.go new file mode 100644 index 0000000000..1b5df41427 --- /dev/null +++ b/e2e/runner/ton/faucet.go @@ -0,0 +1,53 @@ +package ton + +import ( + "context" + "encoding/json" + "fmt" + "net/http" +) + +// Faucet represents the faucet information. +// +//nolint:revive,stylecheck // comes from my-local-ton +type Faucet struct { + InitialBalance int64 `json:"initialBalance"` + PrivateKey string `json:"privateKey"` + PublicKey string `json:"publicKey"` + WalletRawAddress string `json:"walletRawAddress"` + Mnemonic string `json:"mnemonic"` + WalletVersion string `json:"walletVersion"` + WorkChain int32 `json:"workChain"` + SubWalletId int `json:"subWalletId"` + Created bool `json:"created"` +} + +// GetFaucet returns the faucet information. +func GetFaucet(ctx context.Context, url string) (Faucet, error) { + resp, err := get(ctx, url) + if err != nil { + return Faucet{}, err + } + + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return Faucet{}, fmt.Errorf("unexpected response status: %d", resp.StatusCode) + } + + var faucet Faucet + if err := json.NewDecoder(resp.Body).Decode(&faucet); err != nil { + return Faucet{}, err + } + + return faucet, nil +} + +func get(ctx context.Context, url string) (*http.Response, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, err + } + + return http.DefaultClient.Do(req) +} From 058bb77b2000c4a1a472d23b903f972a41ffe775 Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:48:57 +0100 Subject: [PATCH 02/12] refactor ton configs --- cmd/zetae2e/config/clients.go | 20 ++++++++------------ cmd/zetae2e/config/config.go | 3 ++- cmd/zetae2e/config/contracts.go | 5 +++++ cmd/zetae2e/config/local.yml | 14 ++++++++++++-- cmd/zetae2e/config/localnet.yml | 17 ++++++++++++++--- 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/cmd/zetae2e/config/clients.go b/cmd/zetae2e/config/clients.go index 06dda6a7f9..7efefb2bdf 100644 --- a/cmd/zetae2e/config/clients.go +++ b/cmd/zetae2e/config/clients.go @@ -44,8 +44,8 @@ func getClientsFromConfig(ctx context.Context, conf config.Config, account confi } var tonClient *tonrunner.Client - if conf.RPCs.TONSidecarURL != "" { - c, err := getTONClient(ctx, conf.RPCs.TONSidecarURL) + if conf.RPCs.TON != "" { + c, err := getTONClient(ctx, conf.RPCs.TON) if err != nil { return runner.Clients{}, fmt.Errorf("failed to get ton client: %w", err) } @@ -132,17 +132,16 @@ func getEVMClient( return evmClient, evmAuth, nil } -func getTONClient(ctx context.Context, sidecarURL string) (*tonrunner.Client, error) { - if sidecarURL == "" { - return nil, fmt.Errorf("sidecar URL is empty") +// getTONClient resolved tonrunner based on lite-server config (path or url) +func getTONClient(ctx context.Context, configURLOrPath string) (*tonrunner.Client, error) { + if configURLOrPath == "" { + return nil, fmt.Errorf("config is empty") } - sidecar := tonrunner.NewSidecarClient(sidecarURL) - // It might take some time to bootstrap the sidecar cfg, err := retry.DoTypedWithRetry( func() (*tonconfig.GlobalConfigurationFile, error) { - return tonconfig.FromURL(ctx, sidecar.LiteServerURL()) + return tonconfig.FromSource(ctx, configURLOrPath) }, ) @@ -155,10 +154,7 @@ func getTONClient(ctx context.Context, sidecarURL string) (*tonrunner.Client, er return nil, fmt.Errorf("failed to create ton client: %w", err) } - return &tonrunner.Client{ - Client: client, - SidecarClient: sidecar, - }, nil + return &tonrunner.Client{Client: client}, nil } func GetZetacoreClient(conf config.Config) (zetacore_rpc.Clients, error) { diff --git a/cmd/zetae2e/config/config.go b/cmd/zetae2e/config/config.go index 96ba899544..92a655f2c2 100644 --- a/cmd/zetae2e/config/config.go +++ b/cmd/zetae2e/config/config.go @@ -31,7 +31,6 @@ func RunnerFromConfig( ctxCancel, account, e2eClients, - logger, opts..., ) @@ -58,6 +57,8 @@ func ExportContractsFromRunner(r *runner.E2ERunner, conf config.Config) config.C conf.Contracts.Solana.GatewayProgramID = config.DoubleQuotedString(r.GatewayProgram.String()) conf.Contracts.Solana.SPLAddr = config.DoubleQuotedString(r.SPLAddr.String()) + conf.Contracts.TON.GatewayAccountID = config.DoubleQuotedString(r.TONGateway.ToRaw()) + if r.SuiGateway != nil { conf.Contracts.Sui.GatewayPackageID = config.DoubleQuotedString(r.SuiGateway.PackageID()) conf.Contracts.Sui.GatewayObjectID = config.DoubleQuotedString(r.SuiGateway.ObjectID()) diff --git a/cmd/zetae2e/config/contracts.go b/cmd/zetae2e/config/contracts.go index 798e21f547..6b94982e15 100644 --- a/cmd/zetae2e/config/contracts.go +++ b/cmd/zetae2e/config/contracts.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/gagliardetto/solana-go" "github.com/stretchr/testify/require" + "github.com/tonkeeper/tongo/ton" "github.com/zeta-chain/protocol-contracts/pkg/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/pkg/gatewayevm.sol" "github.com/zeta-chain/protocol-contracts/pkg/gatewayzevm.sol" @@ -118,6 +119,10 @@ func setContractsFromConfig(r *runner.E2ERunner, conf config.Config) error { r.SPLAddr = solana.MustPublicKeyFromBase58(c.String()) } + if c := conf.Contracts.TON.GatewayAccountID; c != "" { + r.TONGateway = ton.MustParseAccountID(c.String()) + } + // set Sui contracts suiPackageID := conf.Contracts.Sui.GatewayPackageID suiGatewayID := conf.Contracts.Sui.GatewayObjectID diff --git a/cmd/zetae2e/config/local.yml b/cmd/zetae2e/config/local.yml index 70ce5ad8be..a308d67542 100644 --- a/cmd/zetae2e/config/local.yml +++ b/cmd/zetae2e/config/local.yml @@ -36,6 +36,11 @@ additional_accounts: evm_address: "0xf67deecc3B15F9CEeF5eba3468ed601f3e0B9de2" private_key: "2b3306a8ac43dbf0e350b87876c131e7e12bd49563a16de9ce8aeb664b94d559" solana_private_key: "4yqSQxDeTBvn86BuxcN5jmZb2gaobFXrBqu8kiE9rZxNkVMe3LfXmFigRsU4sRp7vk4vVP1ZCFiejDKiXBNWvs2C" + user_ton: + bech32_address: "zeta13a5yvmysdsncc704e093wy5wm0akp394tkrwje" + evm_address: "0x8f68466C906c278c79F5CbcB17128EdBfb60C4b5" + private_key: "a85f64e560fbef77422272b162915da8170152cf3983567b66f20a5494544591" + ton_private_key: "6c87e1b6852388d9b3438492807b4f47a03486d9ec0c11a65e2ebc48a706dbac" user_sui: bech32_address: "zeta1qluk7yfyqfejwss64lqmn7de6svudcedz94zs2" evm_address: "0x07F96F1124027327421AAFc1B9F9B9D419C6e32d" @@ -112,7 +117,8 @@ rpcs: zetacore_grpc: "localhost:9090" zetacore_rpc: "http://localhost:26657" solana: "http://localhost:8899" - ton_sidecar_url: "http://localhost:8111" + ton_liteserver_config: "http://ton:8111/lite-client.json" + ton_faucet: "http://ton:8111/faucet.json" zetaclient_metrics: "http://localhost:8886" contracts: zevm: @@ -139,4 +145,8 @@ contracts: test_dapp_v2: "0xa825eAa55b497AF892faca73a3797046C10B7c23" solana: gateway_program_id: "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d" - spl: "" \ No newline at end of file + spl: "" + ton: + # e.g. "0:31503e3dd1df464216e4c4ca0eee3a40b812822c8539823e009b0720fab527b5" + # unique on each e2e as it's partially derived from TSS address + gateway_account_id: "" diff --git a/cmd/zetae2e/config/localnet.yml b/cmd/zetae2e/config/localnet.yml index 25fbaa4444..683307aa49 100644 --- a/cmd/zetae2e/config/localnet.yml +++ b/cmd/zetae2e/config/localnet.yml @@ -34,6 +34,11 @@ additional_accounts: evm_address: "0xf67deecc3B15F9CEeF5eba3468ed601f3e0B9de2" private_key: "2b3306a8ac43dbf0e350b87876c131e7e12bd49563a16de9ce8aeb664b94d559" solana_private_key: "4yqSQxDeTBvn86BuxcN5jmZb2gaobFXrBqu8kiE9rZxNkVMe3LfXmFigRsU4sRp7vk4vVP1ZCFiejDKiXBNWvs2C" + user_ton: + bech32_address: "zeta13a5yvmysdsncc704e093wy5wm0akp394tkrwje" + evm_address: "0x8f68466C906c278c79F5CbcB17128EdBfb60C4b5" + private_key: "a85f64e560fbef77422272b162915da8170152cf3983567b66f20a5494544591" + ton_private_key: "6c87e1b6852388d9b3438492807b4f47a03486d9ec0c11a65e2ebc48a706dbac" user_sui: bech32_address: "zeta1qluk7yfyqfejwss64lqmn7de6svudcedz94zs2" evm_address: "0x07F96F1124027327421AAFc1B9F9B9D419C6e32d" @@ -108,14 +113,20 @@ rpcs: disable_tls: true params: regnet solana: "http://solana:8899" - ton_sidecar_url: "http://ton:8000" + # can be either path or url to json config + ton_liteserver_config: "http://ton:8000/lite-client.json" + ton_faucet: "http://ton:8000/faucet.json" sui: "http://sui:9000" sui_faucet: "http://sui:9123" zetacore_grpc: "zetacore0:9090" zetacore_rpc: "http://zetacore0:26657" zetaclient_metrics: "http://zetaclient0:8886" contracts: -# configure localnet solana gateway program id + # configure localnet solana gateway program id solana: gateway_program_id: "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d" - spl: "" \ No newline at end of file + spl: "" + ton: + # e.g. "0:31503e3dd1df464216e4c4ca0eee3a40b812822c8539823e009b0720fab527b5" + # unique on each e2e as it's partially derived from TSS address + gateway_account_id: "" From 52a7d4a6000eb4b6a470667328e5d19b6e4ad399 Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:49:45 +0100 Subject: [PATCH 03/12] fund ton user; update scripts --- contrib/localnet/orchestrator/start-zetae2e.sh | 3 +++ contrib/localnet/scripts/start-zetacored.sh | 3 +++ contrib/localnet/scripts/wait-for-ton.sh | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index 989a9fb134..3bddf17699 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -115,6 +115,9 @@ fund_eth_from_config '.additional_accounts.user_bitcoin_withdraw.evm_address' 10 # unlock solana tester accounts fund_eth_from_config '.additional_accounts.user_solana.evm_address' 10000 "solana tester" +# unlock ton tester accounts +fund_eth_from_config '.additional_accounts.user_ton.evm_address' 10000 "ton tester" + # unlock sui tester accounts fund_eth_from_config '.additional_accounts.user_sui.evm_address' 10000 "sui tester" diff --git a/contrib/localnet/scripts/start-zetacored.sh b/contrib/localnet/scripts/start-zetacored.sh index 4444238f64..f248a7f100 100755 --- a/contrib/localnet/scripts/start-zetacored.sh +++ b/contrib/localnet/scripts/start-zetacored.sh @@ -246,6 +246,9 @@ then # solana tester address=$(yq -r '.additional_accounts.user_solana.bech32_address' /root/config.yml) zetacored add-genesis-account "$address" 100000000000000000000000000azeta +# ton tester + address=$(yq -r '.additional_accounts.user_ton.bech32_address' /root/config.yml) + zetacored add-genesis-account "$address" 100000000000000000000000000azeta # sui tester address=$(yq -r '.additional_accounts.user_sui.bech32_address' /root/config.yml) zetacored add-genesis-account "$address" 100000000000000000000000000azeta# migration tester diff --git a/contrib/localnet/scripts/wait-for-ton.sh b/contrib/localnet/scripts/wait-for-ton.sh index 411572e3df..c48b93970d 100755 --- a/contrib/localnet/scripts/wait-for-ton.sh +++ b/contrib/localnet/scripts/wait-for-ton.sh @@ -1,7 +1,7 @@ #!/bin/bash timeout_seconds=300 # 5 minutes -poll_interval=10 # Check every 10 seconds +poll_interval=5 # Check every 5 seconds status_url="http://ton:8000/status" From a35a56a65890f5eeb9cd587b779e1388bfd58e80 Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:50:21 +0100 Subject: [PATCH 04/12] add sentinel error --- zetaclient/chains/ton/config/config.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zetaclient/chains/ton/config/config.go b/zetaclient/chains/ton/config/config.go index e0621fb813..6337b56448 100644 --- a/zetaclient/chains/ton/config/config.go +++ b/zetaclient/chains/ton/config/config.go @@ -2,7 +2,6 @@ package config import ( "context" - "fmt" "net/http" "net/url" "time" @@ -15,6 +14,8 @@ import ( type GlobalConfigurationFile = config.GlobalConfigurationFile +var ErrDownload = errors.New("failed to download config file") + // Getter represents LiteAPI config params getter. // Don't be confused because config param in this case represent on-chain params, // not lite-client's ADNL json config to connect to the network. @@ -40,13 +41,13 @@ func FromURL(ctx context.Context, url string) (*GlobalConfigurationFile, error) res, err := http.DefaultClient.Do(req) if err != nil { - return nil, err + return nil, errors.Wrap(ErrDownload, err.Error()) } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return nil, fmt.Errorf("failed to download config file: %s", res.Status) + return nil, errors.Wrap(ErrDownload, res.Status) } return config.ParseConfig(res.Body) From 96a0cac9978d6cae1581085d8b02ff80e34b72dc Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:51:12 +0100 Subject: [PATCH 05/12] more refactoring --- cmd/zetae2e/init.go | 2 +- cmd/zetae2e/local/local.go | 17 ++++++++++++----- cmd/zetae2e/local/ton.go | 6 +----- cmd/zetae2e/root.go | 4 ++-- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/cmd/zetae2e/init.go b/cmd/zetae2e/init.go index 6f98c24102..60bf01e628 100644 --- a/cmd/zetae2e/init.go +++ b/cmd/zetae2e/init.go @@ -31,7 +31,7 @@ func NewInitCmd() *cobra.Command { InitCmd.Flags(). StringVar(&initConf.RPCs.Solana, "solanaURL", initConf.RPCs.Solana, "--solanaURL http://solana:8899") InitCmd.Flags(). - StringVar(&initConf.RPCs.TONSidecarURL, "tonSidecarURL", initConf.RPCs.TONSidecarURL, "--tonSidecarURL http://ton:8000") + StringVar(&initConf.RPCs.TON, "tonURL", initConf.RPCs.TON, "--tonURL http://ton:8000/lite-client.json") InitCmd.Flags().StringVar(&initConf.ZetaChainID, "chainID", initConf.ZetaChainID, "--chainID athens_101-1") InitCmd.Flags().StringVar(&configFile, local.FlagConfigFile, "e2e.config", "--cfg ./e2e.config") diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 7f71b7075c..e6647e154d 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -141,11 +141,6 @@ func localE2ETest(cmd *cobra.Command, _ []string) { conf, err := GetConfig(cmd) noError(err) - // temporary spaghetti to overcome e2e flags limitations - if !testTON { - conf.RPCs.TONSidecarURL = "" - } - // initialize context ctx, timeoutCancel := context.WithTimeoutCause(context.Background(), TestTimeout, ErrTopLevelTimeout) defer timeoutCancel() @@ -182,6 +177,11 @@ func localE2ETest(cmd *cobra.Command, _ []string) { ) noError(err) + // Drop this cond after TON e2e is included in the default suite + if !testTON { + conf.RPCs.TON = "" + } + // initialize deployer runner with config deployerRunner, err := zetae2econfig.RunnerFromConfig( ctx, @@ -257,6 +257,13 @@ func localE2ETest(cmd *cobra.Command, _ []string) { // Update the chain params to contains protocol contract addresses deployerRunner.UpdateProtocolContractsInChainParams() + if testTON { + deployerRunner.SetupTON( + conf.RPCs.TONFaucet, + conf.AdditionalAccounts.UserTON, + ) + } + if testSui { deployerRunner.SetupSui(conf.RPCs.SuiFaucet) } diff --git a/cmd/zetae2e/local/ton.go b/cmd/zetae2e/local/ton.go index bbbbd991de..4d158513d9 100644 --- a/cmd/zetae2e/local/ton.go +++ b/cmd/zetae2e/local/ton.go @@ -23,7 +23,7 @@ func tonTestRoutine( "ton", conf, deployerRunner, - conf.DefaultAccount, + conf.AdditionalAccounts.UserTON, runner.NewLogger(verbose, color.FgCyan, "ton"), runner.WithZetaTxServer(deployerRunner.ZetaTxServer), ) @@ -39,10 +39,6 @@ func tonTestRoutine( return errors.Wrap(err, "unable to get ton tests to run") } - if err := tonRunner.SetupTON(); err != nil { - return errors.Wrap(err, "unable to setup TON account") - } - if err := tonRunner.RunE2ETests(tests); err != nil { return errors.Wrap(err, "ton tests failed") } diff --git a/cmd/zetae2e/root.go b/cmd/zetae2e/root.go index 28b4b0c003..d7e571e760 100644 --- a/cmd/zetae2e/root.go +++ b/cmd/zetae2e/root.go @@ -6,7 +6,7 @@ import ( "github.com/zeta-chain/node/cmd/zetae2e/local" ) -var asciiArt = ` +const banner = ` _ ____ _______| |_ __ _ ___|___ \ ___ |_ / _ \ __/ _ |/ _ \ __) / _ \ @@ -17,7 +17,7 @@ var asciiArt = ` func NewRootCmd() *cobra.Command { cmd := &cobra.Command{ Use: "zetae2e", - Short: asciiArt, + Short: banner, } cmd.AddCommand( NewRunCmd(), From c44f22b4114f2c66c10d7237bbc4efec8d533df4 Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:51:50 +0100 Subject: [PATCH 06/12] ton pk; account.AsTONWallet --- e2e/config/config.go | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/e2e/config/config.go b/e2e/config/config.go index 8e4adcd41e..9755332584 100644 --- a/e2e/config/config.go +++ b/e2e/config/config.go @@ -3,7 +3,6 @@ package config import ( "crypto/ecdsa" "encoding/hex" - "errors" "fmt" "os" "strings" @@ -13,8 +12,11 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" + "github.com/pkg/errors" + tonwallet "github.com/tonkeeper/tongo/wallet" "gopkg.in/yaml.v3" + "github.com/zeta-chain/node/e2e/runner/ton" "github.com/zeta-chain/node/pkg/contracts/sui" ) @@ -60,9 +62,10 @@ type Account struct { RawPrivateKey DoubleQuotedString `yaml:"private_key"` SolanaAddress DoubleQuotedString `yaml:"solana_address"` SolanaPrivateKey DoubleQuotedString `yaml:"solana_private_key"` + TONPrivateKey DoubleQuotedString `yaml:"ton_private_key"` } -// AdditionalAccounts are extra accounts required to run specific tests +// AdditionalAccounts are extra required to run specific tests type AdditionalAccounts struct { UserLegacyERC20 Account `yaml:"user_legacy_erc20"` UserLegacyZeta Account `yaml:"user_legacy_zeta"` @@ -72,6 +75,7 @@ type AdditionalAccounts struct { UserBitcoinWithdraw Account `yaml:"user_bitcoin_withdraw"` UserSolana Account `yaml:"user_solana"` UserSPL Account `yaml:"user_spl"` + UserTON Account `yaml:"user_ton"` UserSui Account `yaml:"user_sui"` UserMisc Account `yaml:"user_misc"` UserAdmin Account `yaml:"user_admin"` @@ -102,7 +106,8 @@ type RPCs struct { EVM string `yaml:"evm"` Bitcoin BitcoinRPC `yaml:"bitcoin"` Solana string `yaml:"solana"` - TONSidecarURL string `yaml:"ton_sidecar_url"` + TON string `yaml:"ton_liteserver_config"` + TONFaucet string `yaml:"ton_faucet"` Sui string `yaml:"sui"` SuiFaucet string `yaml:"sui_faucet"` ZetaCoreGRPC string `yaml:"zetacore_grpc"` @@ -123,6 +128,7 @@ type Contracts struct { EVM EVM `yaml:"evm"` ZEVM ZEVM `yaml:"zevm"` Solana Solana `yaml:"solana"` + TON TON `yaml:"ton"` Sui Sui `yaml:"sui"` } @@ -132,6 +138,11 @@ type Solana struct { SPLAddr DoubleQuotedString `yaml:"spl"` } +// TON contains the address of predeployed contracts on the TON chain +type TON struct { + GatewayAccountID DoubleQuotedString `yaml:"gateway_account_id"` +} + // Sui contains the addresses of predeployed contracts on the Sui chain type Sui struct { GatewayPackageID DoubleQuotedString `yaml:"gateway_package_id"` @@ -189,6 +200,7 @@ func DefaultConfig() Config { ZetaCoreGRPC: "zetacore0:9090", ZetaCoreRPC: "http://zetacore0:26657", Solana: "http://solana:8899", + TON: "http://ton:8000/lite-client.json", }, ZetaChainID: "athens_101-1", Contracts: Contracts{ @@ -255,6 +267,7 @@ func (a AdditionalAccounts) AsSlice() []Account { a.UserBitcoinDeposit, a.UserBitcoinWithdraw, a.UserSolana, + a.UserTON, a.UserSui, a.UserSPL, a.UserLegacyEther, @@ -351,6 +364,10 @@ func (c *Config) GenerateKeys() error { if err != nil { return err } + c.AdditionalAccounts.UserTON, err = generateAccount() + if err != nil { + return err + } c.AdditionalAccounts.UserSui, err = generateAccount() if err != nil { return err @@ -429,6 +446,18 @@ func (a Account) SuiSigner() (*sui.SignerSecp256k1, error) { return sui.NewSignerSecp256k1(privateKeyBytes), nil } +// AsTONWallet derives TON V5R1 wallet from Account's mnemonic. +// Make sure that the wallet IS deployed on the network. +func (a Account) AsTONWallet(client *ton.Client) (*tonwallet.Wallet, error) { + pk, err := ton.PrivateKeyFromHex(a.TONPrivateKey.String()) + if err != nil { + return nil, errors.Wrap(err, "failed to get private key") + } + + _, w, err := ton.ConstructWalletFromPrivateKey(pk, client) + return w, err +} + // Validate that the address and the private key specified in the // config actually match func (a Account) Validate() error { From b42074927f6b6221576f8eaf78670fea3448a889 Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:52:20 +0100 Subject: [PATCH 07/12] refactor ton setup --- e2e/runner/runner.go | 27 +++++++-- e2e/runner/setup_ton.go | 129 ++++++++++++++++++++++++---------------- e2e/runner/ton.go | 10 ++-- 3 files changed, 104 insertions(+), 62 deletions(-) diff --git a/e2e/runner/runner.go b/e2e/runner/runner.go index b114795059..7e004e510f 100644 --- a/e2e/runner/runner.go +++ b/e2e/runner/runner.go @@ -21,6 +21,7 @@ import ( "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" "github.com/stretchr/testify/require" + "github.com/tonkeeper/tongo/ton" erc20custodyv2 "github.com/zeta-chain/protocol-contracts/pkg/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/pkg/gatewayevm.sol" "github.com/zeta-chain/protocol-contracts/pkg/gatewayzevm.sol" @@ -36,12 +37,10 @@ import ( "github.com/zeta-chain/node/e2e/contracts/erc20" "github.com/zeta-chain/node/e2e/contracts/testdappv2" "github.com/zeta-chain/node/e2e/contracts/zevmswap" - tonrunner "github.com/zeta-chain/node/e2e/runner/ton" "github.com/zeta-chain/node/e2e/txserver" "github.com/zeta-chain/node/e2e/utils" "github.com/zeta-chain/node/pkg/constant" "github.com/zeta-chain/node/pkg/contracts/sui" - toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" "github.com/zeta-chain/node/pkg/contracts/uniswap/v2-core/contracts/uniswapv2factory.sol" uniswapv2router "github.com/zeta-chain/node/pkg/contracts/uniswap/v2-periphery/contracts/uniswapv2router02.sol" authoritytypes "github.com/zeta-chain/node/x/authority/types" @@ -78,8 +77,6 @@ type E2ERunner struct { BTCTSSAddress btcutil.Address BTCDeployerAddress *btcutil.AddressWitnessPubKeyHash SolanaDeployerAddress solana.PublicKey - TONDeployer *tonrunner.Deployer - TONGateway *toncontracts.Gateway FeeCollectorAddress types.AccAddress // all clients. @@ -117,6 +114,9 @@ type E2ERunner struct { GatewayProgram solana.PublicKey SPLAddr solana.PublicKey + // TON related + TONGateway ton.AccountID + // contract Sui SuiGateway *sui.Gateway @@ -274,6 +274,8 @@ func (r *E2ERunner) CopyAddressesFrom(other *E2ERunner) (err error) { r.GatewayProgram = other.GatewayProgram + r.TONGateway = other.TONGateway + r.SuiGateway = other.SuiGateway r.SuiTokenCoinType = other.SuiTokenCoinType r.SuiTokenTreasuryCap = other.SuiTokenTreasuryCap @@ -399,6 +401,13 @@ func (r *E2ERunner) PrintContractAddresses() { r.Logger.Print("GatewayProgram: %s", r.GatewayProgram.String()) r.Logger.Print("SPL: %s", r.SPLAddr.String()) + r.Logger.Print(" --- πŸ“œTON addresses ---") + if !r.TONGateway.IsZero() { + r.Logger.Print("Gateway: %s", r.TONGateway.ToRaw()) + } else { + r.Logger.Print("Gateway: not set! πŸ’€") + } + r.Logger.Print(" --- πŸ“œSui addresses ---") if r.SuiGateway != nil { r.Logger.Print("GatewayPackageID: %s", r.SuiGateway.PackageID()) @@ -454,8 +463,14 @@ func (r *E2ERunner) Errorf(format string, args ...any) { // FailNow implemented to mimic the behavior of testing.T.FailNow func (r *E2ERunner) FailNow() { - r.Logger.Error("Test failed") - r.CtxCancel(fmt.Errorf("FailNow on %s", r.Name)) + err := fmt.Errorf("(*E2ERunner).FailNow for runner %q. Exiting", r.Name) + + r.Logger.Error("Failure: %s", err.Error()) + r.CtxCancel(err) + + // Give some time to other goroutines to finish + time.Sleep(time.Second) + os.Exit(1) } func (r *E2ERunner) requireTxSuccessful(receipt *ethtypes.Receipt, msgAndArgs ...any) { diff --git a/e2e/runner/setup_ton.go b/e2e/runner/setup_ton.go index 173d3d524d..a9a6d43c94 100644 --- a/e2e/runner/setup_ton.go +++ b/e2e/runner/setup_ton.go @@ -1,11 +1,15 @@ package runner import ( - "fmt" + "context" "time" + "cosmossdk.io/math" "github.com/pkg/errors" + "github.com/stretchr/testify/require" + "github.com/tonkeeper/tongo/wallet" + "github.com/zeta-chain/node/e2e/config" "github.com/zeta-chain/node/e2e/runner/ton" "github.com/zeta-chain/node/e2e/utils" "github.com/zeta-chain/node/pkg/chains" @@ -16,74 +20,68 @@ import ( ) // SetupTON setups TON deployer and deploys Gateway contract -func (r *E2ERunner) SetupTON() error { - if r.Clients.TON == nil { - return fmt.Errorf("TON clients are not initialized") - } +func (r *E2ERunner) SetupTON(faucetURL string, userTON config.Account) { + require.NotNil(r, faucetURL, "TON faucet url is empty") + require.NotNil(r, r.Clients.TON, "TON client is not initialized") ctx := r.Ctx // 1. Setup Deployer (acts as a faucet as well) - faucetConfig, err := r.Clients.TON.GetFaucet(ctx) - if err != nil { - return errors.Wrap(err, "unable to get faucet config") - } + faucetConfig, err := ton.GetFaucet(ctx, faucetURL) + require.NoError(r, err, "unable to get faucet config") deployer, err := ton.NewDeployer(r.Clients.TON, faucetConfig) - if err != nil { - return errors.Wrap(err, "unable to create TON deployer") - } + require.NoError(r, err, "unable to create TON deployer") + + deployerID := deployer.GetAddress() - depAddr := deployer.GetAddress() - r.Logger.Print("πŸ’ŽTON Deployer %s (%s)", depAddr.ToRaw(), depAddr.ToHuman(false, true)) + deployerBalance, err := r.Clients.TON.GetBalanceOf(ctx, deployerID, false) + require.NoError(r, err, "unable to get balance of TON deployer") + + r.Logger.Print( + "πŸ’Ž TON Deployer %s; balance %s", + deployerID, + toncontracts.FormatCoins(deployerBalance), + ) // 2. Deploy Gateway - gwAccount, err := ton.ConstructGatewayAccount(depAddr, r.TSSAddress) - if err != nil { - return errors.Wrap(err, "unable to initialize TON gateway") - } + gwAccount, err := ton.ConstructGatewayAccount(deployerID, r.TSSAddress) + require.NoError(r, err, "unable to initialize TON gateway") - if err = deployer.Deploy(ctx, gwAccount, toncontracts.Coins(1)); err != nil { - return errors.Wrapf(err, "unable to deploy TON gateway") - } + err = deployer.Deploy(ctx, gwAccount, toncontracts.Coins(1)) + require.NoError(r, err, "unable to deploy TON gateway") + + // 3. Check that the gateway indeed was deployed and has desired TON balance. + gwBalance, err := r.Clients.TON.GetBalanceOf(ctx, gwAccount.ID, true) + require.NoError(r, err, "unable to get balance of TON gateway") + require.False(r, gwBalance.IsZero(), "TON gateway balance is zero") r.Logger.Print( - "πŸ’ŽTON Gateway deployed %s (%s) with TSS address %s", + "πŸ’Ž TON Gateway deployed %s; balance: %s", gwAccount.ID.ToRaw(), - gwAccount.ID.ToHuman(false, true), - r.TSSAddress.Hex(), + toncontracts.FormatCoins(gwBalance), ) - // 3. Check that the gateway indeed was deployed and has desired TON balance. - gwBalance, err := deployer.GetBalanceOf(ctx, gwAccount.ID, true) - switch { - case err != nil: - return errors.Wrap(err, "unable to get balance of TON gateway") - case gwBalance.IsZero(): - return fmt.Errorf("TON gateway balance is zero") - } + amount := toncontracts.Coins(1000) - // 4. Set chain params & chain nonce - if err := r.ensureTONChainParams(gwAccount); err != nil { - return errors.Wrap(err, "unable to ensure TON chain params") - } + // 4. Provision user account + r.tonProvisionUser(ctx, userTON, deployer, amount) - r.TONDeployer = deployer - r.TONGateway = toncontracts.NewGateway(gwAccount.ID) + // 5. Set chain params & chain nonce + err = r.ensureTONChainParams(gwAccount) + require.NoError(r, err, "unable to ensure TON chain params") - // 5. Deposit 10000 TON deployer to Zevm Auth - veryFirstDeposit := toncontracts.Coins(10000) - zevmRecipient := r.ZEVMAuth.From + gw := toncontracts.NewGateway(gwAccount.ID) - gwDeposit, err := r.TONDeposit(&deployer.Wallet, veryFirstDeposit, zevmRecipient) - switch { - case err != nil: - return errors.Wrap(err, "unable to deposit TON to Zevm Auth") - case gwDeposit.CctxStatus.Status != cctxtypes.CctxStatus_OutboundMined: - return errors.New("gateway deposit CCTX is not mined") - } + // 5. Deposit TON to userTON + zevmRecipient := userTON.EVMAddress() + + cctx, err := r.TONDeposit(gw, &deployer.Wallet, amount, zevmRecipient) + require.NoError(r, err, "unable to deposit TON to userTON (additional account)") + require.Equal(r, cctxtypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) - return nil + // Set runner field + r.TONGateway = gw.AccountID() } func (r *E2ERunner) ensureTONChainParams(gw *ton.AccountInit) error { @@ -125,7 +123,7 @@ func (r *E2ERunner) ensureTONChainParams(gw *ton.AccountInit) error { return errors.Wrap(err, "unable to broadcast TON chain nonce reset tx") } - r.Logger.Print("πŸ’ŽVoted for adding TON chain params (localnet). Waiting for confirmation") + r.Logger.Print("πŸ’Ž Voted for adding TON chain params (localnet). Waiting for confirmation") query := &observertypes.QueryGetChainParamsForChainRequest{ChainId: chainID} @@ -134,7 +132,7 @@ func (r *E2ERunner) ensureTONChainParams(gw *ton.AccountInit) error { for i := 0; i < 10; i++ { _, err := r.ObserverClient.GetChainParamsForChain(r.Ctx, query) if err == nil { - r.Logger.Print("πŸ’ŽTON chain params are set") + r.Logger.Print("πŸ’Ž TON chain params are set") return nil } @@ -143,3 +141,32 @@ func (r *E2ERunner) ensureTONChainParams(gw *ton.AccountInit) error { return errors.New("unable to set TON chain params") } + +// tonProvisionUser deploy & fund ton user account +// that will act as TON sender/receiver in E2E tests +func (r *E2ERunner) tonProvisionUser( + ctx context.Context, + user config.Account, + deployer *ton.Deployer, + amount math.Uint, +) *wallet.Wallet { + pk, err := ton.PrivateKeyFromHex(user.TONPrivateKey.String()) + require.NoError(r, err, "unable to create TON user private key") + + accInit, wt, err := ton.ConstructWalletFromPrivateKey(pk, r.Clients.TON) + require.NoError(r, err, "unable to create wallet from TON user account") + + err = deployer.Deploy(ctx, accInit, amount) + require.NoError(r, err, "unable to deploy TON user wallet %s", wt.GetAddress().ToRaw()) + + balance, err := wt.GetBalance(ctx) + require.NoError(r, err, "unable to get balance of TON user wallet") + + r.Logger.Print( + "πŸ’Ž Config.AdditionalAccounts.UserTON: %s; balance: %s", + wt.GetAddress().ToRaw(), + toncontracts.FormatCoins(math.NewUint(balance)), + ) + + return wt +} diff --git a/e2e/runner/ton.go b/e2e/runner/ton.go index 97b0a6d472..608e76ba29 100644 --- a/e2e/runner/ton.go +++ b/e2e/runner/ton.go @@ -34,13 +34,12 @@ type tonOpts struct { type TONOpt func(t *tonOpts) func TONExpectStatus(status cctypes.CctxStatus) TONOpt { - return func(t *tonOpts) { - t.expectedStatus = status - } + return func(t *tonOpts) { t.expectedStatus = status } } // TONDeposit deposit TON to Gateway contract func (r *E2ERunner) TONDeposit( + gw *toncontracts.Gateway, sender *wallet.Wallet, amount math.Uint, zevmRecipient eth.Address, @@ -61,7 +60,7 @@ func (r *E2ERunner) TONDeposit( ) // Send TX - err := r.TONGateway.SendDeposit(r.Ctx, sender, amount, zevmRecipient, tonDepositSendCode) + err := gw.SendDeposit(r.Ctx, sender, amount, zevmRecipient, tonDepositSendCode) if err != nil { return nil, errors.Wrap(err, "failed to send TON deposit") } @@ -79,6 +78,7 @@ func (r *E2ERunner) TONDeposit( // TONDepositAndCall deposit TON to Gateway contract with call data. func (r *E2ERunner) TONDepositAndCall( + gw *toncontracts.Gateway, sender *wallet.Wallet, amount math.Uint, zevmRecipient eth.Address, @@ -107,7 +107,7 @@ func (r *E2ERunner) TONDepositAndCall( string(callData), ) - err := r.TONGateway.SendDepositAndCall(r.Ctx, sender, amount, zevmRecipient, callData, tonDepositSendCode) + err := gw.SendDepositAndCall(r.Ctx, sender, amount, zevmRecipient, callData, tonDepositSendCode) if err != nil { return nil, errors.Wrap(err, "failed to send TON deposit and call") } From d6ff1c04e2ee5bd705cd8c6810c7e89027f5845e Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:52:31 +0100 Subject: [PATCH 08/12] Fix tests --- e2e/e2etests/test_ton_deposit.go | 14 ++++++----- e2e/e2etests/test_ton_deposit_and_call.go | 19 +++++++++------ e2e/e2etests/test_ton_deposit_refund.go | 11 ++++++++- e2e/e2etests/test_ton_withdrawal.go | 24 +++++++++---------- .../test_ton_withdrawal_concurrent.go | 5 +--- 5 files changed, 43 insertions(+), 30 deletions(-) diff --git a/e2e/e2etests/test_ton_deposit.go b/e2e/e2etests/test_ton_deposit.go index 8b2f1fde32..2b4315bb01 100644 --- a/e2e/e2etests/test_ton_deposit.go +++ b/e2e/e2etests/test_ton_deposit.go @@ -13,25 +13,27 @@ import ( func TestTONDeposit(r *runner.E2ERunner, args []string) { require.Len(r, args, 1) - // Given deployer - ctx, deployer := r.Ctx, r.TONDeployer + ctx := r.Ctx + + // Given gateway + gw := toncontracts.NewGateway(r.TONGateway) // Given amount amount := utils.ParseUint(r, args[0]) // Given approx deposit fee - depositFee, err := r.TONGateway.GetTxFee(ctx, r.Clients.TON, toncontracts.OpDeposit) + depositFee, err := gw.GetTxFee(ctx, r.Clients.TON, toncontracts.OpDeposit) require.NoError(r, err) - // Given sample wallet with a balance of 50 TON - sender, err := deployer.CreateWallet(ctx, toncontracts.Coins(50)) + // Given a sender + sender, err := r.Account.AsTONWallet(r.Clients.TON) require.NoError(r, err) // Given sample EVM address recipient := sample.EthAddress() // ACT - cctx, err := r.TONDeposit(sender, amount, recipient) + cctx, err := r.TONDeposit(gw, sender, amount, recipient) // ASSERT require.NoError(r, err) diff --git a/e2e/e2etests/test_ton_deposit_and_call.go b/e2e/e2etests/test_ton_deposit_and_call.go index 0f329a272d..a1a1b0d536 100644 --- a/e2e/e2etests/test_ton_deposit_and_call.go +++ b/e2e/e2etests/test_ton_deposit_and_call.go @@ -13,30 +13,35 @@ import ( func TestTONDepositAndCall(r *runner.E2ERunner, args []string) { require.Len(r, args, 1) - // Given deployer - ctx, deployer := r.Ctx, r.TONDeployer + ctx := r.Ctx + + // Given gateway + gw := toncontracts.NewGateway(r.TONGateway) // Given amount amount := utils.ParseUint(r, args[0]) // Given approx depositAndCall fee - depositFee, err := r.TONGateway.GetTxFee(ctx, r.Clients.TON, toncontracts.OpDepositAndCall) + depositFee, err := gw.GetTxFee(ctx, r.Clients.TON, toncontracts.OpDepositAndCall) require.NoError(r, err) - // Given sample wallet with a balance of 50 TON - sender, err := deployer.CreateWallet(ctx, toncontracts.Coins(50)) + // Given a sender + sender, err := r.Account.AsTONWallet(r.Clients.TON) require.NoError(r, err) + // Ensure zevmauth user has ZETA balance + // todo check pre-PR code base (prev code) + // Given sample zEVM contract contractAddr, _, contract, err := testcontract.DeployExample(r.ZEVMAuth, r.ZEVMClient) - require.NoError(r, err) + require.NoError(r, err, "unable to deploy example contract") r.Logger.Info("Example zevm contract deployed at: %s", contractAddr.String()) // Given call data callData := []byte("hello from TON!") // ACT - _, err = r.TONDepositAndCall(sender, amount, contractAddr, callData) + _, err = r.TONDepositAndCall(gw, sender, amount, contractAddr, callData) // ASSERT require.NoError(r, err) diff --git a/e2e/e2etests/test_ton_deposit_refund.go b/e2e/e2etests/test_ton_deposit_refund.go index bcce8b7a72..8c100d1100 100644 --- a/e2e/e2etests/test_ton_deposit_refund.go +++ b/e2e/e2etests/test_ton_deposit_refund.go @@ -6,6 +6,7 @@ import ( testcontract "github.com/zeta-chain/node/e2e/contracts/reverter" "github.com/zeta-chain/node/e2e/runner" "github.com/zeta-chain/node/e2e/utils" + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" cctypes "github.com/zeta-chain/node/x/crosschain/types" ) @@ -18,17 +19,25 @@ func TestTONDepositAndCallRefund(r *runner.E2ERunner, args []string) { data = []byte("hello reverter") ) + // Given gateway + gw := toncontracts.NewGateway(r.TONGateway) + // Given deployer mock revert contract // deploy a reverter contract in ZEVM reverterAddr, _, _, err := testcontract.DeployReverter(r.ZEVMAuth, r.ZEVMClient) require.NoError(r, err) r.Logger.Info("Reverter contract deployed at: %s", reverterAddr.String()) + // Given a sender + sender, err := r.Account.AsTONWallet(r.Clients.TON) + require.NoError(r, err) + // ACT // Send a deposit and call transaction from the deployer (faucet) // to the reverter contract cctx, err := r.TONDepositAndCall( - &r.TONDeployer.Wallet, + gw, + sender, amount, reverterAddr, data, diff --git a/e2e/e2etests/test_ton_withdrawal.go b/e2e/e2etests/test_ton_withdrawal.go index 21d58a1c11..cfcd64f76a 100644 --- a/e2e/e2etests/test_ton_withdrawal.go +++ b/e2e/e2etests/test_ton_withdrawal.go @@ -17,10 +17,10 @@ func TestTONWithdraw(r *runner.E2ERunner, args []string) { // ARRANGE require.Len(r, args, 1) - // Given a deployer - _, deployer := r.Ctx, r.TONDeployer + // Given gateway + gw := toncontracts.NewGateway(r.TONGateway) - // And zEVM sender + // Given zEVM sender zevmSender := r.ZEVMAuth.From // Given his ZRC-20 balance @@ -28,21 +28,21 @@ func TestTONWithdraw(r *runner.E2ERunner, args []string) { require.NoError(r, err) r.Logger.Info("zEVM sender's ZRC20 TON balance before withdraw: %d", senderZRC20BalanceBefore) - // Given another TON wallet - tonRecipient, err := deployer.CreateWallet(r.Ctx, toncontracts.Coins(1)) + // Given a receiver + receiver, err := r.Account.AsTONWallet(r.Clients.TON) require.NoError(r, err) - tonRecipientBalanceBefore, err := deployer.GetBalanceOf(r.Ctx, tonRecipient.GetAddress(), true) + receiverBalanceBefore, err := r.Clients.TON.GetBalanceOf(r.Ctx, receiver.GetAddress(), true) require.NoError(r, err) - r.Logger.Info("Recipient's TON balance before withdrawal: %s", toncontracts.FormatCoins(tonRecipientBalanceBefore)) + r.Logger.Info("Recipient's TON balance before withdrawal: %s", toncontracts.FormatCoins(receiverBalanceBefore)) // Given amount to withdraw (and approved amount in TON ZRC20 to cover the gas fee) amount := utils.ParseUint(r, args[0]) approvedAmount := amount.Add(toncontracts.Coins(1)) // ACT - cctx := r.WithdrawTONZRC20(tonRecipient.GetAddress(), amount.BigInt(), approvedAmount.BigInt()) + cctx := r.WithdrawTONZRC20(receiver.GetAddress(), amount.BigInt(), approvedAmount.BigInt()) // ASSERT r.Logger.Info( @@ -50,7 +50,7 @@ func TestTONWithdraw(r *runner.E2ERunner, args []string) { toncontracts.FormatCoins(amount), map[string]any{ "zevm_sender": zevmSender.Hex(), - "ton_recipient": tonRecipient.GetAddress().ToRaw(), + "ton_recipient": receiver.GetAddress().ToRaw(), "ton_amount": toncontracts.FormatCoins(amount), "cctx_index": cctx.Index, "ton_hash": cctx.GetCurrentOutboundParam().Hash, @@ -59,10 +59,10 @@ func TestTONWithdraw(r *runner.E2ERunner, args []string) { ) // Make sure that recipient's TON balance has increased - tonRecipientBalanceAfter, err := deployer.GetBalanceOf(r.Ctx, tonRecipient.GetAddress(), true) + receiverBalanceAfter, err := r.Clients.TON.GetBalanceOf(r.Ctx, receiver.GetAddress(), true) require.NoError(r, err) - r.Logger.Info("Recipient's balance after withdrawal: %s", toncontracts.FormatCoins(tonRecipientBalanceAfter)) + r.Logger.Info("Recipient's balance after withdrawal: %s", toncontracts.FormatCoins(receiverBalanceAfter)) // Make sure that sender's ZRC20 balance has decreased senderZRC20BalanceAfter, err := r.TONZRC20.BalanceOf(&bind.CallOpts{}, zevmSender) @@ -77,7 +77,7 @@ func TestTONWithdraw(r *runner.E2ERunner, args []string) { lt, hash, err := liteapi.TransactionHashFromString(cctx.GetCurrentOutboundParam().Hash) require.NoError(r, err) - txs, err := r.Clients.TON.GetTransactions(r.Ctx, 1, r.TONGateway.AccountID(), lt, hash) + txs, err := r.Clients.TON.GetTransactions(r.Ctx, 1, gw.AccountID(), lt, hash) require.NoError(r, err) require.Len(r, txs, 1) diff --git a/e2e/e2etests/test_ton_withdrawal_concurrent.go b/e2e/e2etests/test_ton_withdrawal_concurrent.go index fb4217013d..0a72f6967e 100644 --- a/e2e/e2etests/test_ton_withdrawal_concurrent.go +++ b/e2e/e2etests/test_ton_withdrawal_concurrent.go @@ -21,9 +21,6 @@ import ( // and that zetaclient tolerates "invalid nonce" error from RPC. func TestTONWithdrawConcurrent(r *runner.E2ERunner, _ []string) { // ARRANGE - // Given a deployer - _, deployer := r.Ctx, r.TONDeployer - const recipientsCount = 10 // Fire withdrawals. Note that zevm sender is r.ZEVMAuth @@ -64,7 +61,7 @@ func TestTONWithdrawConcurrent(r *runner.E2ERunner, _ []string) { r.Logger.Info("Withdrawal #%d complete! cctx index: %s", number, cctx.Index) // Check recipient's balance ON TON - balance, err := deployer.GetBalanceOf(r.Ctx, recipient, false) + balance, err := r.Clients.TON.GetBalanceOf(r.Ctx, recipient, false) require.NoError(r, err, "failed to get balance of %s", recipient.ToRaw()) require.Equal(r, amount.Uint64(), balance.Uint64()) }(i+1, recipient, amount, tx) From 953c800d0a82269c89ecd2bbca0580c1a909d1fc Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:58:12 +0100 Subject: [PATCH 09/12] Livetest toggle --- cmd/zetatool/cctx/inbound_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/zetatool/cctx/inbound_test.go b/cmd/zetatool/cctx/inbound_test.go index 33ae9c8ed1..0bd98ea87f 100644 --- a/cmd/zetatool/cctx/inbound_test.go +++ b/cmd/zetatool/cctx/inbound_test.go @@ -8,9 +8,15 @@ import ( "github.com/zeta-chain/node/cmd/zetatool/cctx" zetatoolcontext "github.com/zeta-chain/node/cmd/zetatool/context" "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/zetaclient/common" ) func Test_InboundBallotIdentifier(t *testing.T) { + if !common.LiveTestEnabled() { + t.Skip("skipping live test") + return + } + tt := []struct { name string inboundHash string From 906f15bc249b7ff4a59efed68f81264e2e2bf386 Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Fri, 28 Feb 2025 23:02:18 +0100 Subject: [PATCH 10/12] Update changelog --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index 6d73cd54bb..72f1e45ba4 100644 --- a/changelog.md +++ b/changelog.md @@ -47,6 +47,7 @@ * [3536](https://github.com/zeta-chain/node/pull/3536) - add e2e test for upgrading solana gateway program * [3560](https://github.com/zeta-chain/node/pull/3560) - initialize Sui E2E deposit tests * [3591](https://github.com/zeta-chain/node/pull/3591) - add a runner for gov proposals in the e2e test. +* [3612](https://github.com/zeta-chain/node/pull/3612) - add support for TON live e2e2 tests ## v28.0.0 From 3a750150a9f14c694f238fea7560907811359f74 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Fri, 28 Feb 2025 14:43:07 -0800 Subject: [PATCH 11/12] use solana private key --- cmd/zetae2e/config/local.yml | 2 +- cmd/zetae2e/config/localnet.yml | 2 +- e2e/config/config.go | 23 ++++++++++++----------- e2e/e2etests/test_ton_deposit.go | 2 +- e2e/e2etests/test_ton_deposit_and_call.go | 2 +- e2e/e2etests/test_ton_deposit_refund.go | 2 +- e2e/e2etests/test_ton_withdrawal.go | 2 +- e2e/runner/setup_ton.go | 5 +---- 8 files changed, 19 insertions(+), 21 deletions(-) diff --git a/cmd/zetae2e/config/local.yml b/cmd/zetae2e/config/local.yml index a308d67542..d488b2e757 100644 --- a/cmd/zetae2e/config/local.yml +++ b/cmd/zetae2e/config/local.yml @@ -40,7 +40,7 @@ additional_accounts: bech32_address: "zeta13a5yvmysdsncc704e093wy5wm0akp394tkrwje" evm_address: "0x8f68466C906c278c79F5CbcB17128EdBfb60C4b5" private_key: "a85f64e560fbef77422272b162915da8170152cf3983567b66f20a5494544591" - ton_private_key: "6c87e1b6852388d9b3438492807b4f47a03486d9ec0c11a65e2ebc48a706dbac" + solana_private_key: "2AB2oDXWey3uhwYVj4bbJ4cGbz7R2ZMePJpY5r84KyVeUq2z89nsfWgcnb1sH1jUvRaCxXV2DBwMNUobQUfTbeqq" user_sui: bech32_address: "zeta1qluk7yfyqfejwss64lqmn7de6svudcedz94zs2" evm_address: "0x07F96F1124027327421AAFc1B9F9B9D419C6e32d" diff --git a/cmd/zetae2e/config/localnet.yml b/cmd/zetae2e/config/localnet.yml index 683307aa49..d1af8e1486 100644 --- a/cmd/zetae2e/config/localnet.yml +++ b/cmd/zetae2e/config/localnet.yml @@ -38,7 +38,7 @@ additional_accounts: bech32_address: "zeta13a5yvmysdsncc704e093wy5wm0akp394tkrwje" evm_address: "0x8f68466C906c278c79F5CbcB17128EdBfb60C4b5" private_key: "a85f64e560fbef77422272b162915da8170152cf3983567b66f20a5494544591" - ton_private_key: "6c87e1b6852388d9b3438492807b4f47a03486d9ec0c11a65e2ebc48a706dbac" + solana_private_key: "2AB2oDXWey3uhwYVj4bbJ4cGbz7R2ZMePJpY5r84KyVeUq2z89nsfWgcnb1sH1jUvRaCxXV2DBwMNUobQUfTbeqq" user_sui: bech32_address: "zeta1qluk7yfyqfejwss64lqmn7de6svudcedz94zs2" evm_address: "0x07F96F1124027327421AAFc1B9F9B9D419C6e32d" diff --git a/e2e/config/config.go b/e2e/config/config.go index 9755332584..77658a545e 100644 --- a/e2e/config/config.go +++ b/e2e/config/config.go @@ -2,6 +2,7 @@ package config import ( "crypto/ecdsa" + "crypto/ed25519" "encoding/hex" "fmt" "os" @@ -12,6 +13,7 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" + "github.com/gagliardetto/solana-go" "github.com/pkg/errors" tonwallet "github.com/tonkeeper/tongo/wallet" "gopkg.in/yaml.v3" @@ -62,7 +64,6 @@ type Account struct { RawPrivateKey DoubleQuotedString `yaml:"private_key"` SolanaAddress DoubleQuotedString `yaml:"solana_address"` SolanaPrivateKey DoubleQuotedString `yaml:"solana_private_key"` - TONPrivateKey DoubleQuotedString `yaml:"ton_private_key"` } // AdditionalAccounts are extra required to run specific tests @@ -446,19 +447,19 @@ func (a Account) SuiSigner() (*sui.SignerSecp256k1, error) { return sui.NewSignerSecp256k1(privateKeyBytes), nil } -// AsTONWallet derives TON V5R1 wallet from Account's mnemonic. -// Make sure that the wallet IS deployed on the network. -func (a Account) AsTONWallet(client *ton.Client) (*tonwallet.Wallet, error) { - pk, err := ton.PrivateKeyFromHex(a.TONPrivateKey.String()) - if err != nil { - return nil, errors.Wrap(err, "failed to get private key") - } +// AsTONWallet derives TON V5R1 wallet solana private key +func (a Account) AsTONWallet(client *ton.Client) (*ton.AccountInit, *tonwallet.Wallet, error) { + pk := solana.MustPrivateKeyFromBase58(a.SolanaPrivateKey.String()) + + // Extract the seed bytes (first 32 bytes) from the ed25519 private key + // ed25519 private key is 64 bytes: 32 bytes seed + 32 bytes public key + seed := pk[:ed25519.SeedSize] + + rawPk := ed25519.NewKeyFromSeed(seed) - _, w, err := ton.ConstructWalletFromPrivateKey(pk, client) - return w, err + return ton.ConstructWalletFromPrivateKey(rawPk, client) } -// Validate that the address and the private key specified in the // config actually match func (a Account) Validate() error { privateKey, err := a.PrivateKey() diff --git a/e2e/e2etests/test_ton_deposit.go b/e2e/e2etests/test_ton_deposit.go index 2b4315bb01..2974e48b37 100644 --- a/e2e/e2etests/test_ton_deposit.go +++ b/e2e/e2etests/test_ton_deposit.go @@ -26,7 +26,7 @@ func TestTONDeposit(r *runner.E2ERunner, args []string) { require.NoError(r, err) // Given a sender - sender, err := r.Account.AsTONWallet(r.Clients.TON) + _, sender, err := r.Account.AsTONWallet(r.Clients.TON) require.NoError(r, err) // Given sample EVM address diff --git a/e2e/e2etests/test_ton_deposit_and_call.go b/e2e/e2etests/test_ton_deposit_and_call.go index a1a1b0d536..67a89b71c1 100644 --- a/e2e/e2etests/test_ton_deposit_and_call.go +++ b/e2e/e2etests/test_ton_deposit_and_call.go @@ -26,7 +26,7 @@ func TestTONDepositAndCall(r *runner.E2ERunner, args []string) { require.NoError(r, err) // Given a sender - sender, err := r.Account.AsTONWallet(r.Clients.TON) + _, sender, err := r.Account.AsTONWallet(r.Clients.TON) require.NoError(r, err) // Ensure zevmauth user has ZETA balance diff --git a/e2e/e2etests/test_ton_deposit_refund.go b/e2e/e2etests/test_ton_deposit_refund.go index 8c100d1100..e84860a291 100644 --- a/e2e/e2etests/test_ton_deposit_refund.go +++ b/e2e/e2etests/test_ton_deposit_refund.go @@ -29,7 +29,7 @@ func TestTONDepositAndCallRefund(r *runner.E2ERunner, args []string) { r.Logger.Info("Reverter contract deployed at: %s", reverterAddr.String()) // Given a sender - sender, err := r.Account.AsTONWallet(r.Clients.TON) + _, sender, err := r.Account.AsTONWallet(r.Clients.TON) require.NoError(r, err) // ACT diff --git a/e2e/e2etests/test_ton_withdrawal.go b/e2e/e2etests/test_ton_withdrawal.go index cfcd64f76a..e4d02f3c2e 100644 --- a/e2e/e2etests/test_ton_withdrawal.go +++ b/e2e/e2etests/test_ton_withdrawal.go @@ -29,7 +29,7 @@ func TestTONWithdraw(r *runner.E2ERunner, args []string) { r.Logger.Info("zEVM sender's ZRC20 TON balance before withdraw: %d", senderZRC20BalanceBefore) // Given a receiver - receiver, err := r.Account.AsTONWallet(r.Clients.TON) + _, receiver, err := r.Account.AsTONWallet(r.Clients.TON) require.NoError(r, err) receiverBalanceBefore, err := r.Clients.TON.GetBalanceOf(r.Ctx, receiver.GetAddress(), true) diff --git a/e2e/runner/setup_ton.go b/e2e/runner/setup_ton.go index a9a6d43c94..ac78402389 100644 --- a/e2e/runner/setup_ton.go +++ b/e2e/runner/setup_ton.go @@ -150,10 +150,7 @@ func (r *E2ERunner) tonProvisionUser( deployer *ton.Deployer, amount math.Uint, ) *wallet.Wallet { - pk, err := ton.PrivateKeyFromHex(user.TONPrivateKey.String()) - require.NoError(r, err, "unable to create TON user private key") - - accInit, wt, err := ton.ConstructWalletFromPrivateKey(pk, r.Clients.TON) + accInit, wt, err := user.AsTONWallet(r.Clients.TON) require.NoError(r, err, "unable to create wallet from TON user account") err = deployer.Deploy(ctx, accInit, amount) From 66a427f98badefab16847fa6a4ed9666c583787b Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Wed, 5 Mar 2025 10:44:52 +0100 Subject: [PATCH 12/12] Address PR comments --- changelog.md | 2 +- cmd/zetae2e/config/local.yml | 3 ++- cmd/zetae2e/config/localnet.yml | 4 ++-- contrib/localnet/scripts/start-zetacored.sh | 2 +- e2e/config/config.go | 4 ++-- e2e/e2etests/test_ton_deposit_and_call.go | 5 +---- e2e/runner/setup_ton.go | 2 +- 7 files changed, 10 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 72f1e45ba4..72c0219b68 100644 --- a/changelog.md +++ b/changelog.md @@ -47,7 +47,7 @@ * [3536](https://github.com/zeta-chain/node/pull/3536) - add e2e test for upgrading solana gateway program * [3560](https://github.com/zeta-chain/node/pull/3560) - initialize Sui E2E deposit tests * [3591](https://github.com/zeta-chain/node/pull/3591) - add a runner for gov proposals in the e2e test. -* [3612](https://github.com/zeta-chain/node/pull/3612) - add support for TON live e2e2 tests +* [3612](https://github.com/zeta-chain/node/pull/3612) - add support for TON live e2e tests ## v28.0.0 diff --git a/cmd/zetae2e/config/local.yml b/cmd/zetae2e/config/local.yml index d488b2e757..94c88eb0da 100644 --- a/cmd/zetae2e/config/local.yml +++ b/cmd/zetae2e/config/local.yml @@ -117,7 +117,8 @@ rpcs: zetacore_grpc: "localhost:9090" zetacore_rpc: "http://localhost:26657" solana: "http://localhost:8899" - ton_liteserver_config: "http://ton:8111/lite-client.json" + # ton lite-server config url or path + ton: "http://ton:8111/lite-client.json" ton_faucet: "http://ton:8111/faucet.json" zetaclient_metrics: "http://localhost:8886" contracts: diff --git a/cmd/zetae2e/config/localnet.yml b/cmd/zetae2e/config/localnet.yml index d1af8e1486..cc92276317 100644 --- a/cmd/zetae2e/config/localnet.yml +++ b/cmd/zetae2e/config/localnet.yml @@ -113,8 +113,8 @@ rpcs: disable_tls: true params: regnet solana: "http://solana:8899" - # can be either path or url to json config - ton_liteserver_config: "http://ton:8000/lite-client.json" + # ton lite-server config url or path + ton: "http://ton:8000/lite-client.json" ton_faucet: "http://ton:8000/faucet.json" sui: "http://sui:9000" sui_faucet: "http://sui:9123" diff --git a/contrib/localnet/scripts/start-zetacored.sh b/contrib/localnet/scripts/start-zetacored.sh index cb8ba6f2cf..25b5c81b90 100755 --- a/contrib/localnet/scripts/start-zetacored.sh +++ b/contrib/localnet/scripts/start-zetacored.sh @@ -248,7 +248,7 @@ then zetacored add-genesis-account "$address" 100000000000000000000000000azeta # ton tester address=$(yq -r '.additional_accounts.user_ton.bech32_address' /root/config.yml) - zetacored add-genesis-account "$address" 100000000000000000000000000azeta + zetacored add-genesis-account "$address" 10000000000000000000000000azeta # sui tester address=$(yq -r '.additional_accounts.user_sui.bech32_address' /root/config.yml) zetacored add-genesis-account "$address" 100000000000000000000000000azeta# migration tester diff --git a/e2e/config/config.go b/e2e/config/config.go index 77658a545e..ef4586615e 100644 --- a/e2e/config/config.go +++ b/e2e/config/config.go @@ -66,7 +66,7 @@ type Account struct { SolanaPrivateKey DoubleQuotedString `yaml:"solana_private_key"` } -// AdditionalAccounts are extra required to run specific tests +// AdditionalAccounts are extra accounts required to run specific tests type AdditionalAccounts struct { UserLegacyERC20 Account `yaml:"user_legacy_erc20"` UserLegacyZeta Account `yaml:"user_legacy_zeta"` @@ -107,7 +107,7 @@ type RPCs struct { EVM string `yaml:"evm"` Bitcoin BitcoinRPC `yaml:"bitcoin"` Solana string `yaml:"solana"` - TON string `yaml:"ton_liteserver_config"` + TON string `yaml:"ton"` TONFaucet string `yaml:"ton_faucet"` Sui string `yaml:"sui"` SuiFaucet string `yaml:"sui_faucet"` diff --git a/e2e/e2etests/test_ton_deposit_and_call.go b/e2e/e2etests/test_ton_deposit_and_call.go index 67a89b71c1..cca7137f2a 100644 --- a/e2e/e2etests/test_ton_deposit_and_call.go +++ b/e2e/e2etests/test_ton_deposit_and_call.go @@ -29,10 +29,7 @@ func TestTONDepositAndCall(r *runner.E2ERunner, args []string) { _, sender, err := r.Account.AsTONWallet(r.Clients.TON) require.NoError(r, err) - // Ensure zevmauth user has ZETA balance - // todo check pre-PR code base (prev code) - - // Given sample zEVM contract + // Given sample zEVM contract deployed by userTON account contractAddr, _, contract, err := testcontract.DeployExample(r.ZEVMAuth, r.ZEVMClient) require.NoError(r, err, "unable to deploy example contract") r.Logger.Info("Example zevm contract deployed at: %s", contractAddr.String()) diff --git a/e2e/runner/setup_ton.go b/e2e/runner/setup_ton.go index ac78402389..a8a5f5ca7d 100644 --- a/e2e/runner/setup_ton.go +++ b/e2e/runner/setup_ton.go @@ -21,7 +21,7 @@ import ( // SetupTON setups TON deployer and deploys Gateway contract func (r *E2ERunner) SetupTON(faucetURL string, userTON config.Account) { - require.NotNil(r, faucetURL, "TON faucet url is empty") + require.NotEmpty(r, faucetURL, "TON faucet url is empty") require.NotNil(r, r.Clients.TON, "TON client is not initialized") ctx := r.Ctx