Skip to content

Commit

Permalink
Merge pull request #122 from ava-labs/add-teleporter
Browse files Browse the repository at this point in the history
Add teleporter
  • Loading branch information
felipemadero authored Aug 30, 2024
2 parents b972d4a + a064ff8 commit 2c429fa
Show file tree
Hide file tree
Showing 6 changed files with 331 additions and 8 deletions.
4 changes: 4 additions & 0 deletions constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,8 @@ const (
StakerCertFileName = "staker.crt"
StakerKeyFileName = "staker.key"
BLSKeyFileName = "signer.key"

// github
AvaLabsOrg = "ava-labs"
TeleporterRepoName = "teleporter"
)
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (

require (
github.com/onsi/gomega v1.33.1 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.26.0 // indirect
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down
222 changes: 214 additions & 8 deletions teleporter/teleporter.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,219 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// Copyright (C) 2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package teleporter

import "math/big"
import (
"fmt"
"math/big"
"os"

type Info struct {
Version string
FundedAddress string
FundedBalance *big.Int
MessengerDeployerAddress string
RelayerAddress string
"github.com/ava-labs/avalanche-tooling-sdk-go/constants"
"github.com/ava-labs/avalanche-tooling-sdk-go/evm"
"github.com/ava-labs/avalanche-tooling-sdk-go/utils"
"github.com/ethereum/go-ethereum/common"
)

const (
releaseURL = "https://github.com/ava-labs/teleporter/releases/download/%s/"
messengerContractAddressURLFmt = releaseURL + "/TeleporterMessenger_Contract_Address_%s.txt"
messengerDeployerAddressURLFmt = releaseURL + "/TeleporterMessenger_Deployer_Address_%s.txt"
messengerDeployerTxURLFmt = releaseURL + "/TeleporterMessenger_Deployment_Transaction_%s.txt"
registryBytecodeURLFmt = releaseURL + "/TeleporterRegistry_Bytecode_%s.txt"
)

var (
// 10 TOKENS
messengerDeployerRequiredBalance = big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10))
// 600 TOKENS
ICMRequiredBalance = big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(600))
)

func GetLatestVersion() (string, error) {
return utils.GetLatestGithubReleaseVersion(constants.AvaLabsOrg, constants.TeleporterRepoName, "")
}

func getURLs(version string) (string, string, string, string) {
messengerContractAddressURL := fmt.Sprintf(messengerContractAddressURLFmt, version, version)
messengerDeployerAddressURL := fmt.Sprintf(messengerDeployerAddressURLFmt, version, version)
messengerDeployerTxURL := fmt.Sprintf(messengerDeployerTxURLFmt, version, version)
registryBytecodeURL := fmt.Sprintf(registryBytecodeURLFmt, version, version)
return messengerContractAddressURL, messengerDeployerAddressURL, messengerDeployerTxURL, registryBytecodeURL
}

type Deployer struct {
messengerContractAddress []byte
messengerDeployerAddress []byte
messengerDeployerTx []byte
registryBytecode []byte
}

func (t *Deployer) CheckAssets() error {
if len(t.messengerContractAddress) == 0 || len(t.messengerDeployerAddress) == 0 || len(t.messengerDeployerTx) == 0 || len(t.registryBytecode) == 0 {
return fmt.Errorf("teleporter assets has not been initialized")
}
return nil
}

func (t *Deployer) GetAssets() ([]byte, []byte, []byte, []byte) {
return t.messengerContractAddress, t.messengerDeployerAddress, t.messengerDeployerTx, t.registryBytecode
}

func (t *Deployer) SetAssets(
messengerContractAddress []byte,
messengerDeployerAddress []byte,
messengerDeployerTx []byte,
registryBytecode []byte,
) {
t.messengerContractAddress = messengerContractAddress
t.messengerDeployerAddress = messengerDeployerAddress
t.messengerDeployerTx = messengerDeployerTx
t.registryBytecode = registryBytecode
}

func (t *Deployer) LoadAssets(
messengerContractAddressPath string,
messengerDeployerAddressPath string,
messengerDeployerTxPath string,
registryBytecodePath string,
) error {
var err error
if messengerContractAddressPath != "" {
if t.messengerContractAddress, err = os.ReadFile(messengerContractAddressPath); err != nil {
return err
}
}
if messengerDeployerAddressPath != "" {
if t.messengerDeployerAddress, err = os.ReadFile(messengerDeployerAddressPath); err != nil {
return err
}
}
if messengerDeployerTxPath != "" {
if t.messengerDeployerTx, err = os.ReadFile(messengerDeployerTxPath); err != nil {
return err
}
}
if registryBytecodePath != "" {
if t.registryBytecode, err = os.ReadFile(registryBytecodePath); err != nil {
return err
}
}
return nil
}

func (t *Deployer) DownloadAssets(version string) error {
var err error
messengerContractAddressURL, messengerDeployerAddressURL, messengerDeployerTxURL, registryBytecodeURL := getURLs(version)
if t.messengerContractAddress, err = utils.HTTPGet(messengerContractAddressURL, ""); err != nil {
return err
}
if t.messengerDeployerAddress, err = utils.HTTPGet(messengerDeployerAddressURL, ""); err != nil {
return err
}
if t.messengerDeployerTx, err = utils.HTTPGet(messengerDeployerTxURL, ""); err != nil {
return err
}
if t.registryBytecode, err = utils.HTTPGet(registryBytecodeURL, ""); err != nil {
return err
}
return nil
}

// Deploys messenger and registry
// If messenger is already deployed, will avoid deploying registry
// (to force, set deployMessenger to false)
func (t *Deployer) Deploy(
rpcURL string,
privateKey string,
deployMessenger bool,
deployRegistry bool,
) (bool, string, string, error) {
var (
messengerAddress string
registryAddress string
messengerAlreadyDeployed bool
err error
)
if deployMessenger {
messengerAlreadyDeployed, messengerAddress, err = t.DeployMessenger(
rpcURL,
privateKey,
)
}
if err == nil && deployRegistry {
if !deployMessenger || !messengerAlreadyDeployed {
registryAddress, err = t.DeployRegistry(rpcURL, privateKey)
}
}
return messengerAlreadyDeployed, messengerAddress, registryAddress, err
}

func (t *Deployer) DeployMessenger(
rpcURL string,
privateKey string,
) (bool, string, error) {
if err := t.CheckAssets(); err != nil {
return false, "", err
}
client, err := evm.GetClient(rpcURL)
if err != nil {
return false, "", err
}
if messengerAlreadyDeployed, err := evm.ContractAlreadyDeployed(client, string(t.messengerContractAddress)); err != nil {
return false, "", fmt.Errorf("failure making a request to %s: %w", rpcURL, err)
} else if messengerAlreadyDeployed {
return true, string(t.messengerContractAddress), nil
}
messengerDeployerBalance, err := evm.GetAddressBalance(
client,
string(t.messengerDeployerAddress),
)
if err != nil {
return false, "", err
}
if messengerDeployerBalance.Cmp(messengerDeployerRequiredBalance) < 0 {
toFund := big.NewInt(0).Sub(messengerDeployerRequiredBalance, messengerDeployerBalance)
if err := evm.FundAddress(
client,
privateKey,
string(t.messengerDeployerAddress),
toFund,
); err != nil {
return false, "", err
}
}
if err := evm.IssueTx(client, string(t.messengerDeployerTx)); err != nil {
return false, "", err
}
return false, string(t.messengerContractAddress), nil
}

func (t *Deployer) DeployRegistry(
rpcURL string,
privateKey string,
) (string, error) {
if err := t.CheckAssets(); err != nil {
return "", err
}
messengerContractAddress := common.HexToAddress(string(t.messengerContractAddress))
type ProtocolRegistryEntry struct {
Version *big.Int
ProtocolAddress common.Address
}
constructorInput := []ProtocolRegistryEntry{
{
Version: big.NewInt(1),
ProtocolAddress: messengerContractAddress,
},
}
registryAddress, err := evm.DeployContract(
rpcURL,
privateKey,
t.registryBytecode,
"([(uint256, address)])",
constructorInput,
)
if err != nil {
return "", err
}
return registryAddress.Hex(), nil
}
77 changes: 77 additions & 0 deletions utils/github.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package utils

import (
"encoding/json"
"fmt"

"golang.org/x/mod/semver"
)

const githubVersionTagName = "tag_name"

func GetLatestGithubReleaseURL(org, repo string) string {
return fmt.Sprintf("%s/%s", GetGithubReleasesURL(org, repo), "latest")
}

func GetGithubReleasesURL(org, repo string) string {
return fmt.Sprintf("https://api.github.com/repos/%s/%s/releases", org, repo)
}

// GetLatestGithubReleaseVersion returns the latest available release version from github
func GetLatestGithubReleaseVersion(org, repo, authToken string) (string, error) {
url := GetLatestGithubReleaseURL(org, repo)
jsonBytes, err := HTTPGet(url, authToken)
if err != nil {
return "", err
}

var jsonStr map[string]interface{}
if err := json.Unmarshal(jsonBytes, &jsonStr); err != nil {
return "", fmt.Errorf("failed to unmarshal binary json version string: %w", err)
}

version := jsonStr[githubVersionTagName].(string)
if !semver.IsValid(version) {
return "", fmt.Errorf("invalid version string: %s", version)
}

return version, nil
}

func GetAllGithubReleaseVersions(org, repo, authToken string) ([]string, error) {
url := GetGithubReleasesURL(org, repo)
jsonBytes, err := HTTPGet(url, authToken)
if err != nil {
return nil, err
}

var releaseArr []map[string]interface{}
if err := json.Unmarshal(jsonBytes, &releaseArr); err != nil {
return nil, fmt.Errorf("failed to unmarshal binary json version string: %w", err)
}

releases := make([]string, len(releaseArr))
for i, r := range releaseArr {
version := r[githubVersionTagName].(string)
if !semver.IsValid(version) {
return nil, fmt.Errorf("invalid version string: %s", version)
}
releases[i] = version
}

return releases, nil
}

// GetLatestGithubPreReleaseVersion returns the latest available pre release version from github
func GetLatestGithubPreReleaseVersion(org, repo, authToken string) (string, error) {
releases, err := GetAllGithubReleaseVersions(org, repo, authToken)
if err != nil {
return "", err
}
if len(releases) == 0 {
return "", fmt.Errorf("no releases found for org %s repo %s", org, repo)
}
return releases[0], nil
}
33 changes: 33 additions & 0 deletions utils/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package utils

import (
"fmt"
"io"
"net/http"
)

func HTTPGet(url, authToken string) ([]byte, error) {
request, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("failed downloading %s: %w", url, err)
}
if authToken != "" {
// to avoid rate limitation issues
request.Header.Set("authorization", fmt.Sprintf("Bearer %s", authToken))
}
resp, err := http.DefaultClient.Do(request)
if err != nil {
return nil, fmt.Errorf("failed downloading %s: %w", url, err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed downloading %s: unexpected http status code: %d", url, resp.StatusCode)
}
defer resp.Body.Close()
bs, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed downloading %s: %w", url, err)
}
return bs, nil
}

0 comments on commit 2c429fa

Please sign in to comment.