diff --git a/cmd/interchaincmd/tokentransferrercmd/deploy.go b/cmd/interchaincmd/tokentransferrercmd/deploy.go index 33b56095a..cded2f221 100644 --- a/cmd/interchaincmd/tokentransferrercmd/deploy.go +++ b/cmd/interchaincmd/tokentransferrercmd/deploy.go @@ -9,10 +9,12 @@ import ( "time" cmdflags "github.com/ava-labs/avalanche-cli/cmd/flags" + "github.com/ava-labs/avalanche-cli/pkg/application" "github.com/ava-labs/avalanche-cli/pkg/cobrautils" "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanche-cli/pkg/contract" "github.com/ava-labs/avalanche-cli/pkg/ictt" + "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/networkoptions" "github.com/ava-labs/avalanche-cli/pkg/precompiles" "github.com/ava-labs/avalanche-cli/pkg/prompts" @@ -101,6 +103,43 @@ func deploy(_ *cobra.Command, args []string) error { return CallDeploy(args, deployFlags) } +func getHomeKeyAndAddress(app *application.Avalanche, network models.Network, homeFlags HomeFlags) (string, string, error) { + // First check if there is a genesis key able to be used. + genesisAddress, genesisPrivateKey, err := contract.GetEVMSubnetPrefundedKey( + app, + network, + homeFlags.chainFlags, + ) + if err != nil { + return "", "", err + } + + // Propmt for the key to be used. + // Note that this key must have enough funds to cover gas cost on the + // home chain, and also enough of the token on the home chain to collateralize + // the remote chain if it is a native token remote. + homeKey, err := prompts.PromptPrivateKey( + app.Prompt, + "pay for home deployment fees, and collateralization (if necessary)", + app.GetKeyDir(), + app.GetKey, + genesisAddress, + genesisPrivateKey, + ) + if err != nil { + return "", "", err + } + + // Calculate the address for the key. + pk, err := crypto.HexToECDSA(homeKey) + if err != nil { + return "", "", err + } + homeKeyAddress := crypto.PubkeyToAddress(pk.PublicKey).Hex() + + return homeKey, homeKeyAddress, nil +} + func CallDeploy(_ []string, flags DeployFlags) error { if !ictt.FoundryIsInstalled() { if err := ictt.InstallFoundry(); err != nil { @@ -304,41 +343,11 @@ func CallDeploy(_ []string, flags DeployFlags) error { } } - var ( - homeKey string - homeKeyAddress string - ) - if flags.homeFlags.homeAddress == "" { - genesisAddress, genesisPrivateKey, err := contract.GetEVMSubnetPrefundedKey( - app, - network, - flags.homeFlags.chainFlags, - ) - if err != nil { - return err - } - homeKey, err = flags.homeFlags.privateKeyFlags.GetPrivateKey(app, genesisPrivateKey) - if err != nil { - return err - } - if homeKey == "" { - homeKey, err = prompts.PromptPrivateKey( - app.Prompt, - "pay for home deploy fees", - app.GetKeyDir(), - app.GetKey, - genesisAddress, - genesisPrivateKey, - ) - if err != nil { - return err - } - } - pk, err := crypto.HexToECDSA(homeKey) - if err != nil { - return err - } - homeKeyAddress = crypto.PubkeyToAddress(pk.PublicKey).Hex() + // Get the key to be used to deploy the token home contract and collateralize the remote + // in the case that it is a native token remote. + homeKey, homeKeyAddress, err := getHomeKeyAndAddress(app, network, flags.homeFlags) + if err != nil { + return err } // Home Contract Validations @@ -483,7 +492,6 @@ func CallDeploy(_ []string, flags DeployFlags) error { if err := ictt.BuildContracts(app); err != nil { return err } - ux.Logger.PrintToUser("") // Home Deploy icttSrcDir, err := ictt.RepoDir(app) @@ -667,8 +675,10 @@ func CallDeploy(_ []string, flags DeployFlags) error { return err } } + ux.Logger.PrintToUser("Remote Deployed to %s", remoteRPCEndpoint) + ux.Logger.PrintToUser("Remote Address: %s", remoteAddress) - if err := ictt.RegisterERC20Remote( + if err := ictt.RegisterRemote( remoteRPCEndpoint, remoteKey, remoteAddress, @@ -679,6 +689,7 @@ func CallDeploy(_ []string, flags DeployFlags) error { checkInterval := 100 * time.Millisecond checkTimeout := 10 * time.Second t0 := time.Now() + var collateralNeeded *big.Int for { registeredRemote, err := ictt.TokenHomeGetRegisteredRemote( homeRPCEndpoint, @@ -690,6 +701,7 @@ func CallDeploy(_ []string, flags DeployFlags) error { return err } if registeredRemote.Registered { + collateralNeeded = registeredRemote.CollateralNeeded break } elapsed := time.Since(t0) @@ -699,19 +711,21 @@ func CallDeploy(_ []string, flags DeployFlags) error { time.Sleep(checkInterval) } - if flags.remoteFlags.native { + // Collateralize the remote contract on the home contract if necessary + if collateralNeeded.Cmp(big.NewInt(0)) != 0 { err = ictt.TokenHomeAddCollateral( homeRPCEndpoint, homeAddress, homeKey, remoteBlockchainID, remoteAddress, - remoteSupply, + collateralNeeded, ) if err != nil { return err } + // Check that the remote is collateralized on the home contract now. registeredRemote, err := ictt.TokenHomeGetRegisteredRemote( homeRPCEndpoint, homeAddress, @@ -724,7 +738,10 @@ func CallDeploy(_ []string, flags DeployFlags) error { if registeredRemote.CollateralNeeded.Cmp(big.NewInt(0)) != 0 { return fmt.Errorf("failure setting collateral in home endpoint: remaining collateral=%d", registeredRemote.CollateralNeeded) } + } + if flags.remoteFlags.native { + ux.Logger.PrintToUser("Enabling native token remote contract to mint native tokens") if err := precompiles.SetEnabled( remoteRPCEndpoint, precompiles.NativeMinterPrecompile, @@ -734,6 +751,7 @@ func CallDeploy(_ []string, flags DeployFlags) error { return err } + // Send a single token unit to report that the remote is collateralized. err = ictt.Send( homeRPCEndpoint, homeAddress, @@ -785,8 +803,5 @@ func CallDeploy(_ []string, flags DeployFlags) error { } } - ux.Logger.PrintToUser("Remote Deployed to %s", remoteRPCEndpoint) - ux.Logger.PrintToUser("Remote Address: %s", remoteAddress) - return nil } diff --git a/cmd/keycmd/list.go b/cmd/keycmd/list.go index 568878e1b..7170e7f2d 100644 --- a/cmd/keycmd/list.go +++ b/cmd/keycmd/list.go @@ -558,28 +558,44 @@ func getEvmBasedChainAddrInfo( if err != nil { return addressInfos, err } + + // Ignore contract address access errors as those may depend on network tokenSymbol, err := token.Symbol(nil) - if err == nil { - // just ignore contract address access errors as those may depend on network - balance, err := token.BalanceOf(nil, common.HexToAddress(cChainAddr)) - if err != nil { - return addressInfos, err - } - formattedBalance, err := formatCChainBalance(balance) - if err != nil { - return addressInfos, err - } - info := addressInfo{ - kind: kind, - name: name, - chain: chainName, - token: fmt.Sprintf("%s (%s.)", tokenSymbol, tokenAddress[:6]), - address: cChainAddr, - balance: formattedBalance, - network: network.Name(), - } - addressInfos = append(addressInfos, info) + if err != nil { + continue + } + + // Get the raw balance for the given token. + balance, err := token.BalanceOf(nil, common.HexToAddress(cChainAddr)) + if err != nil { + return addressInfos, err + } + + // Get the decimal count for the token to format the balance. + // Note: decimals() is not officially part of the IERC20 interface, but is a common extension. + decimals, err := token.Decimals(nil) + if err != nil { + return addressInfos, err + } + + // Format the balance to a human-readable string. + var formattedBalance string + if useGwei { + formattedBalance = fmt.Sprintf("%d", balance) + } else { + formattedBalance = utils.FormatAmount(balance, decimals) + } + + info := addressInfo{ + kind: kind, + name: name, + chain: chainName, + token: fmt.Sprintf("%s (%s.)", tokenSymbol, tokenAddress[:6]), + address: cChainAddr, + balance: formattedBalance, + network: network.Name(), } + addressInfos = append(addressInfos, info) } } return addressInfos, nil diff --git a/pkg/ictt/deploy.go b/pkg/ictt/deploy.go index 93433d444..657de44fd 100644 --- a/pkg/ictt/deploy.go +++ b/pkg/ictt/deploy.go @@ -10,6 +10,7 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/contract" "github.com/ava-labs/avalanche-cli/pkg/utils" + "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ethereum/go-ethereum/common" ) @@ -26,11 +27,12 @@ type TokenRemoteSettings struct { TokenHomeDecimals uint8 } -func RegisterERC20Remote( +func RegisterRemote( rpcURL string, privateKey string, remoteAddress common.Address, ) error { + ux.Logger.PrintToUser("Registering remote contract with home contract") feeInfo := TeleporterFeeInfo{ Amount: big.NewInt(0), } diff --git a/pkg/ictt/operate.go b/pkg/ictt/operate.go index 6b173e8b5..02689dc85 100644 --- a/pkg/ictt/operate.go +++ b/pkg/ictt/operate.go @@ -8,6 +8,7 @@ import ( "math/big" "github.com/ava-labs/avalanche-cli/pkg/contract" + "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanchego/ids" "github.com/ethereum/go-ethereum/common" ) @@ -458,6 +459,7 @@ func TokenHomeAddCollateral( remoteAddress common.Address, amount *big.Int, ) error { + ux.Logger.PrintToUser("Collateralizing remote contract on the home chain") endpointKind, err := GetEndpointKind( rpcURL, homeAddress,