Skip to content

Commit

Permalink
feat(ton): TON observer 💎 (#2896)
Browse files Browse the repository at this point in the history
* Use chainParams from base observer

* Improve base observer Start() semantics

* Add pkg/ticker options

* Add TON to pkg/chains & protos

* Add liteapi wrapper client; locate first tx

* Add TON tx scraper

* Add client.GetTransactionsUntil

* Gateway WIP

* Implement Gateway inbound tx parsing

* Add Gateway tx filtration

* Add GetBlockHeader cache; Add masterchain seqno. Implement watchInbound

* Improve ton contracts pkg

* Add IsTONChain()

* Refactor Gateway package

* Implement samples for TON

* Add liteClient mocks

* Add unit tests for inbound TON observer

* Localnet: add TON ZRC20

* Wire the TON observer into the orchestrator

* Add TON chain params of the fly!

* TON deposits E2E wip

* Fix bugs during cctx;

* TON Deposits E2E 🫡✅

* TON Deposit And Call E2E

* Merge fixes

* Update changelog

* gosec

* Improve testing

* Simplify ticker.Stop(). Leverage ctx.cancel()

* Simplify E2E

* Simplify liteapi semantics

* Fix comments

* Update zetaclient/chains/base/observer.go

Co-authored-by: Francisco de Borja Aranda Castillejo <[email protected]>

* Add gw explanatory comments; address PR comments

* Apply fixes for AI suggestions

* Fix upgrade tests

---------

Co-authored-by: Francisco de Borja Aranda Castillejo <[email protected]>
  • Loading branch information
swift1337 and Francisco de Borja Aranda Castillejo authored Oct 9, 2024
1 parent 1470fdc commit b20c3f1
Show file tree
Hide file tree
Showing 84 changed files with 3,943 additions and 422 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* [2904](https://github.com/zeta-chain/node/pull/2904) - integrate authenticated calls smart contract functionality into protocol
* [2919](https://github.com/zeta-chain/node/pull/2919) - add inbound sender to revert context
* [2957](https://github.com/zeta-chain/node/pull/2957) - enable Bitcoin inscription support on testnet
* [2896](https://github.com/zeta-chain/node/pull/2896) - add TON inbound observation

### Refactor

Expand Down
1 change: 1 addition & 0 deletions cmd/zetae2e/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func ExportContractsFromRunner(r *runner.E2ERunner, conf config.Config) config.C
conf.Contracts.ZEVM.ERC20ZRC20Addr = config.DoubleQuotedString(r.ERC20ZRC20Addr.Hex())
conf.Contracts.ZEVM.BTCZRC20Addr = config.DoubleQuotedString(r.BTCZRC20Addr.Hex())
conf.Contracts.ZEVM.SOLZRC20Addr = config.DoubleQuotedString(r.SOLZRC20Addr.Hex())
conf.Contracts.ZEVM.TONZRC20Addr = config.DoubleQuotedString(r.TONZRC20Addr.Hex())
conf.Contracts.ZEVM.UniswapFactoryAddr = config.DoubleQuotedString(r.UniswapV2FactoryAddr.Hex())
conf.Contracts.ZEVM.UniswapRouterAddr = config.DoubleQuotedString(r.UniswapV2RouterAddr.Hex())
conf.Contracts.ZEVM.ConnectorZEVMAddr = config.DoubleQuotedString(r.ConnectorZEVMAddr.Hex())
Expand Down
11 changes: 11 additions & 0 deletions cmd/zetae2e/config/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ func setContractsFromConfig(r *runner.E2ERunner, conf config.Config) error {
}
}

if c := conf.Contracts.ZEVM.TONZRC20Addr; c != "" {
r.TONZRC20Addr, err = c.AsEVMAddress()
if err != nil {
return fmt.Errorf("invalid TONZRC20Addr: %w", err)
}
r.TONZRC20, err = zrc20.NewZRC20(r.TONZRC20Addr, r.ZEVMClient)
if err != nil {
return err
}
}

if c := conf.Contracts.ZEVM.UniswapFactoryAddr; c != "" {
r.UniswapV2FactoryAddr, err = c.AsEVMAddress()
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) {

tonTests := []string{
e2etests.TestTONDepositName,
e2etests.TestTONDepositAndCallName,
}

eg.Go(tonTestRoutine(conf, deployerRunner, verbose, tonTests...))
Expand Down
1 change: 1 addition & 0 deletions cmd/zetae2e/local/ton.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func tonTestRoutine(
deployerRunner,
conf.DefaultAccount,
runner.NewLogger(verbose, color.FgCyan, "ton"),
runner.WithZetaTxServer(deployerRunner.ZetaTxServer),
)
if err != nil {
return errors.Wrap(err, "unable to init ton test runner")
Expand Down
4 changes: 4 additions & 0 deletions docs/openapi/openapi.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56998,7 +56998,9 @@ definitions:
- bitcoin
- op_stack
- solana_consensus
- catchain_consensus
default: ethereum
description: '- catchain_consensus: ton'
title: |-
Consensus represents the consensus algorithm used by the chain
this can represent the consensus of a L1
Expand All @@ -57014,6 +57016,7 @@ definitions:
- optimism
- base
- solana
- ton
default: eth
title: |-
Network represents the network of the chain
Expand Down Expand Up @@ -57048,6 +57051,7 @@ definitions:
- no_vm
- evm
- svm
- tvm
default: no_vm
title: |-
Vm represents the virtual machine type of the chain to support smart
Expand Down
1 change: 1 addition & 0 deletions e2e/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ type ZEVM struct {
ERC20ZRC20Addr DoubleQuotedString `yaml:"erc20_zrc20"`
BTCZRC20Addr DoubleQuotedString `yaml:"btc_zrc20"`
SOLZRC20Addr DoubleQuotedString `yaml:"sol_zrc20"`
TONZRC20Addr DoubleQuotedString `yaml:"ton_zrc20"`
UniswapFactoryAddr DoubleQuotedString `yaml:"uniswap_factory"`
UniswapRouterAddr DoubleQuotedString `yaml:"uniswap_router"`
ConnectorZEVMAddr DoubleQuotedString `yaml:"connector_zevm"`
Expand Down
13 changes: 11 additions & 2 deletions e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ const (
/**
* TON tests
*/
TestTONDepositName = "ton_deposit"
TestTONDepositName = "ton_deposit"
TestTONDepositAndCallName = "ton_deposit_and_call"

/*
Bitcoin tests
Expand Down Expand Up @@ -445,10 +446,18 @@ var AllE2ETests = []runner.E2ETest{
TestTONDepositName,
"deposit TON into ZEVM",
[]runner.ArgDefinition{
{Description: "amount in nano tons", DefaultValue: "900000000"}, // 0.9 TON
{Description: "amount in nano tons", DefaultValue: "1000000000"}, // 1.0 TON
},
TestTONDeposit,
),
runner.NewE2ETest(
TestTONDepositAndCallName,
"deposit TON into ZEVM and call a contract",
[]runner.ArgDefinition{
{Description: "amount in nano tons", DefaultValue: "1000000000"}, // 1.0 TON
},
TestTONDepositAndCall,
),
/*
Bitcoin tests
*/
Expand Down
5 changes: 5 additions & 0 deletions e2e/e2etests/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"math/big"
"strconv"

"cosmossdk.io/math"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
Expand Down Expand Up @@ -144,6 +145,10 @@ func parseBigInt(t require.TestingT, s string) *big.Int {
return v
}

func parseUint(t require.TestingT, s string) math.Uint {
return math.NewUintFromBigInt(parseBigInt(t, s))
}

// bigIntFromFloat64 takes float64 (e.g. 0.001) that represents btc amount
// and converts it to big.Int for downstream usage.
func btcAmountFromFloat64(t require.TestingT, amount float64) *big.Int {
Expand Down
60 changes: 41 additions & 19 deletions e2e/e2etests/test_ton_deposit.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,64 @@
package e2etests

import (
"time"

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

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/runner/ton"
"github.com/zeta-chain/node/pkg/chains"
"github.com/zeta-chain/node/testutil/sample"
cctypes "github.com/zeta-chain/node/x/crosschain/types"
)

// TestTONDeposit (!) This boilerplate is a demonstration of E2E capabilities for TON integration
// Actual Deposit test is not implemented yet.
func TestTONDeposit(r *runner.E2ERunner, _ []string) {
ctx, deployer := r.Ctx, r.TONDeployer
func TestTONDeposit(r *runner.E2ERunner, args []string) {
require.Len(r, args, 1)

// Given deployer
deployerBalance, err := deployer.GetBalance(ctx)
require.NoError(r, err, "failed to get deployer balance")
require.NotZero(r, deployerBalance, "deployer balance is zero")
ctx, deployer, chain := r.Ctx, r.TONDeployer, chains.TONLocalnet

// Given amount
amount := parseUint(r, args[0])

// https://github.com/zeta-chain/protocol-contracts-ton/blob/main/contracts/gateway.fc#L28
// (will be optimized & dynamic in the future)
depositFee := math.NewUint(10_000_000)

// Given sample wallet with a balance of 50 TON
sender, err := deployer.CreateWallet(ctx, ton.TONCoins(50))
require.NoError(r, err)

// That was funded (again) but the faucet
_, err = deployer.Fund(ctx, sender.GetAddress(), ton.TONCoins(30))
// Given sample EVM address
recipient := sample.EthAddress()

// ACT
err = r.TONDeposit(sender, amount, recipient)

// ASSERT
require.NoError(r, err)

// Check sender balance
sb, err := sender.GetBalance(ctx)
// Wait for CCTX mining
filter := func(cctx *cctypes.CrossChainTx) bool {
return cctx.InboundParams.SenderChainId == chain.ChainId &&
cctx.InboundParams.Sender == sender.GetAddress().ToRaw()
}

cctx := r.WaitForSpecificCCTX(filter, time.Minute)

// Check CCTX
expectedDeposit := amount.Sub(depositFee)

require.Equal(r, sender.GetAddress().ToRaw(), cctx.InboundParams.Sender)
require.Equal(r, expectedDeposit.Uint64(), cctx.InboundParams.Amount.Uint64())

// Check receiver's balance
balance, err := r.TONZRC20.BalanceOf(&bind.CallOpts{}, recipient)
require.NoError(r, err)

senderBalance := math.NewUint(sb)
r.Logger.Info("Recipient's zEVM TON balance after deposit: %d", balance.Uint64())

// note that it's not exactly 80 TON, but 79.99... due to gas fees
// We'll tackle gas math later.
r.Logger.Print(
"Balance of sender (%s): %s",
sender.GetAddress().ToHuman(false, true),
ton.FormatCoins(senderBalance),
)
require.Equal(r, expectedDeposit.Uint64(), balance.Uint64())
}
69 changes: 69 additions & 0 deletions e2e/e2etests/test_ton_deposit_and_call.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package e2etests

import (
"time"

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

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/runner/ton"
"github.com/zeta-chain/node/e2e/utils"
"github.com/zeta-chain/node/pkg/chains"
testcontract "github.com/zeta-chain/node/testutil/contracts"
cctypes "github.com/zeta-chain/node/x/crosschain/types"
)

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

// Given deployer
ctx, deployer, chain := r.Ctx, r.TONDeployer, chains.TONLocalnet

// Given amount
amount := parseUint(r, args[0])

// https://github.com/zeta-chain/protocol-contracts-ton/blob/main/contracts/gateway.fc#L28
// (will be optimized & dynamic in the future)
depositFee := math.NewUint(10_000_000)

// Given sample wallet with a balance of 50 TON
sender, err := deployer.CreateWallet(ctx, ton.TONCoins(50))
require.NoError(r, err)

// Given sample zEVM contract
contractAddr, _, contract, err := testcontract.DeployExample(r.ZEVMAuth, r.ZEVMClient)
require.NoError(r, err)
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)

// ASSERT
require.NoError(r, err)

// Wait for CCTX mining
filter := func(cctx *cctypes.CrossChainTx) bool {
return cctx.InboundParams.SenderChainId == chain.ChainId &&
cctx.InboundParams.Sender == sender.GetAddress().ToRaw()
}

r.WaitForSpecificCCTX(filter, time.Minute)

expectedDeposit := amount.Sub(depositFee)

// check if example contract has been called, bar value should be set to amount
utils.MustHaveCalledExampleContract(r, contract, expectedDeposit.BigInt())

// Check receiver's balance
balance, err := r.TONZRC20.BalanceOf(&bind.CallOpts{}, contractAddr)
require.NoError(r, err)

r.Logger.Info("Contract's zEVM TON balance after deposit: %d", balance.Uint64())

require.Equal(r, expectedDeposit.Uint64(), balance.Uint64())
}
12 changes: 10 additions & 2 deletions e2e/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"
"github.com/tonkeeper/tongo/ton"
"github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/erc20custody.sol"
zetaeth "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zeta.eth.sol"
zetaconnectoreth "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zetaconnector.eth.sol"
Expand All @@ -40,6 +39,7 @@ import (
"github.com/zeta-chain/node/e2e/txserver"
"github.com/zeta-chain/node/e2e/utils"
"github.com/zeta-chain/node/pkg/contracts/testdappv2"
toncontracts "github.com/zeta-chain/node/pkg/contracts/ton"
authoritytypes "github.com/zeta-chain/node/x/authority/types"
crosschaintypes "github.com/zeta-chain/node/x/crosschain/types"
fungibletypes "github.com/zeta-chain/node/x/fungible/types"
Expand Down Expand Up @@ -73,7 +73,7 @@ type E2ERunner struct {
BTCDeployerAddress *btcutil.AddressWitnessPubKeyHash
SolanaDeployerAddress solana.PublicKey
TONDeployer *tonrunner.Deployer
TONGateway ton.AccountID
TONGateway *toncontracts.Gateway

// all clients.
// a reference to this type is required to enable creating a new E2ERunner.
Expand Down Expand Up @@ -127,6 +127,8 @@ type E2ERunner struct {
BTCZRC20 *zrc20.ZRC20
SOLZRC20Addr ethcommon.Address
SOLZRC20 *zrc20.ZRC20
TONZRC20Addr ethcommon.Address
TONZRC20 *zrc20.ZRC20
UniswapV2FactoryAddr ethcommon.Address
UniswapV2Factory *uniswapv2factory.UniswapV2Factory
UniswapV2RouterAddr ethcommon.Address
Expand Down Expand Up @@ -230,6 +232,7 @@ func (r *E2ERunner) CopyAddressesFrom(other *E2ERunner) (err error) {
r.ETHZRC20Addr = other.ETHZRC20Addr
r.BTCZRC20Addr = other.BTCZRC20Addr
r.SOLZRC20Addr = other.SOLZRC20Addr
r.TONZRC20Addr = other.TONZRC20Addr
r.UniswapV2FactoryAddr = other.UniswapV2FactoryAddr
r.UniswapV2RouterAddr = other.UniswapV2RouterAddr
r.ConnectorZEVMAddr = other.ConnectorZEVMAddr
Expand Down Expand Up @@ -275,6 +278,10 @@ func (r *E2ERunner) CopyAddressesFrom(other *E2ERunner) (err error) {
if err != nil {
return err
}
r.TONZRC20, err = zrc20.NewZRC20(r.TONZRC20Addr, r.ZEVMClient)
if err != nil {
return err
}
r.UniswapV2Factory, err = uniswapv2factory.NewUniswapV2Factory(r.UniswapV2FactoryAddr, r.ZEVMClient)
if err != nil {
return err
Expand Down Expand Up @@ -359,6 +366,7 @@ func (r *E2ERunner) PrintContractAddresses() {
r.Logger.Print("ERC20ZRC20: %s", r.ERC20ZRC20Addr.Hex())
r.Logger.Print("BTCZRC20: %s", r.BTCZRC20Addr.Hex())
r.Logger.Print("SOLZRC20: %s", r.SOLZRC20Addr.Hex())
r.Logger.Print("TONZRC20: %s", r.TONZRC20Addr.Hex())
r.Logger.Print("UniswapFactory: %s", r.UniswapV2FactoryAddr.Hex())
r.Logger.Print("UniswapRouter: %s", r.UniswapV2RouterAddr.Hex())
r.Logger.Print("ConnectorZEVM: %s", r.ConnectorZEVMAddr.Hex())
Expand Down
Loading

0 comments on commit b20c3f1

Please sign in to comment.