-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #122 from ava-labs/add-teleporter
Add teleporter
- Loading branch information
Showing
6 changed files
with
331 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |