github.com/MetalBlockchain/metalgo@v1.11.9/tests/e2e/x/interchain_workflow.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package x 5 6 import ( 7 "math/big" 8 9 "github.com/MetalBlockchain/coreth/plugin/evm" 10 "github.com/stretchr/testify/require" 11 12 "github.com/MetalBlockchain/metalgo/ids" 13 "github.com/MetalBlockchain/metalgo/tests/fixture/e2e" 14 "github.com/MetalBlockchain/metalgo/utils/constants" 15 "github.com/MetalBlockchain/metalgo/utils/crypto/secp256k1" 16 "github.com/MetalBlockchain/metalgo/utils/set" 17 "github.com/MetalBlockchain/metalgo/utils/units" 18 "github.com/MetalBlockchain/metalgo/vms/components/avax" 19 "github.com/MetalBlockchain/metalgo/vms/secp256k1fx" 20 "github.com/MetalBlockchain/metalgo/wallet/subnet/primary/common" 21 22 ginkgo "github.com/onsi/ginkgo/v2" 23 ) 24 25 var _ = e2e.DescribeXChain("[Interchain Workflow]", ginkgo.Label(e2e.UsesCChainLabel), func() { 26 require := require.New(ginkgo.GinkgoT()) 27 28 const transferAmount = 10 * units.Avax 29 30 ginkgo.It("should ensure that funds can be transferred from the X-Chain to the C-Chain and the P-Chain", func() { 31 nodeURI := e2e.Env.GetRandomNodeURI() 32 33 ginkgo.By("creating wallet with a funded key to send from and recipient key to deliver to") 34 recipientKey, err := secp256k1.NewPrivateKey() 35 require.NoError(err) 36 keychain := e2e.Env.NewKeychain(1) 37 keychain.Add(recipientKey) 38 baseWallet := e2e.NewWallet(keychain, nodeURI) 39 xWallet := baseWallet.X() 40 cWallet := baseWallet.C() 41 pWallet := baseWallet.P() 42 43 ginkgo.By("defining common configuration") 44 recipientEthAddress := evm.GetEthAddress(recipientKey) 45 xBuilder := xWallet.Builder() 46 xContext := xBuilder.Context() 47 cBuilder := cWallet.Builder() 48 cContext := cBuilder.Context() 49 avaxAssetID := xContext.AVAXAssetID 50 // Use the same owner for sending to X-Chain and importing funds to P-Chain 51 recipientOwner := secp256k1fx.OutputOwners{ 52 Threshold: 1, 53 Addrs: []ids.ShortID{ 54 recipientKey.Address(), 55 }, 56 } 57 // Use the same outputs for both C-Chain and P-Chain exports 58 exportOutputs := []*avax.TransferableOutput{ 59 { 60 Asset: avax.Asset{ 61 ID: avaxAssetID, 62 }, 63 Out: &secp256k1fx.TransferOutput{ 64 Amt: transferAmount, 65 OutputOwners: secp256k1fx.OutputOwners{ 66 Threshold: 1, 67 Addrs: []ids.ShortID{ 68 keychain.Keys[0].Address(), 69 }, 70 }, 71 }, 72 }, 73 } 74 75 ginkgo.By("sending funds from one address to another on the X-Chain", func() { 76 _, err = xWallet.IssueBaseTx( 77 []*avax.TransferableOutput{{ 78 Asset: avax.Asset{ 79 ID: avaxAssetID, 80 }, 81 Out: &secp256k1fx.TransferOutput{ 82 Amt: transferAmount, 83 OutputOwners: recipientOwner, 84 }, 85 }}, 86 e2e.WithDefaultContext(), 87 ) 88 require.NoError(err) 89 }) 90 91 ginkgo.By("checking that the X-Chain recipient address has received the sent funds", func() { 92 balances, err := xWallet.Builder().GetFTBalance(common.WithCustomAddresses(set.Of( 93 recipientKey.Address(), 94 ))) 95 require.NoError(err) 96 require.Positive(balances[avaxAssetID]) 97 }) 98 99 ginkgo.By("exporting AVAX from the X-Chain to the C-Chain", func() { 100 _, err := xWallet.IssueExportTx( 101 cContext.BlockchainID, 102 exportOutputs, 103 e2e.WithDefaultContext(), 104 ) 105 require.NoError(err) 106 }) 107 108 ginkgo.By("initializing a new eth client") 109 ethClient := e2e.NewEthClient(nodeURI) 110 111 ginkgo.By("importing AVAX from the X-Chain to the C-Chain", func() { 112 _, err := cWallet.IssueImportTx( 113 xContext.BlockchainID, 114 recipientEthAddress, 115 e2e.WithDefaultContext(), 116 e2e.WithSuggestedGasPrice(ethClient), 117 ) 118 require.NoError(err) 119 }) 120 121 ginkgo.By("checking that the recipient address has received imported funds on the C-Chain") 122 e2e.Eventually(func() bool { 123 balance, err := ethClient.BalanceAt(e2e.DefaultContext(), recipientEthAddress, nil) 124 require.NoError(err) 125 return balance.Cmp(big.NewInt(0)) > 0 126 }, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see recipient address funded before timeout") 127 128 ginkgo.By("exporting AVAX from the X-Chain to the P-Chain", func() { 129 _, err := xWallet.IssueExportTx( 130 constants.PlatformChainID, 131 exportOutputs, 132 e2e.WithDefaultContext(), 133 ) 134 require.NoError(err) 135 }) 136 137 ginkgo.By("importing AVAX from the X-Chain to the P-Chain", func() { 138 _, err := pWallet.IssueImportTx( 139 xContext.BlockchainID, 140 &recipientOwner, 141 e2e.WithDefaultContext(), 142 ) 143 require.NoError(err) 144 }) 145 146 ginkgo.By("checking that the recipient address has received imported funds on the P-Chain", func() { 147 balances, err := pWallet.Builder().GetBalance(common.WithCustomAddresses(set.Of( 148 recipientKey.Address(), 149 ))) 150 require.NoError(err) 151 require.Positive(balances[avaxAssetID]) 152 }) 153 154 e2e.CheckBootstrapIsPossible(e2e.Env.GetNetwork()) 155 }) 156 })