mirror of
https://github.com/luxfi/sdk.git
synced 2026-10-30 15:19:23 +00:00
Lux Partners Limited is not the entity behind this work. Every place the old name stood — copyright lines, site footers, brand config, legal and compliance text — now names the company that actually holds it. lux.fund is the exception and is not renamed to match: that site belongs to Lux Assets Management LLC, a different company, and it says so. Two kinds of line were left for a person rather than rewritten. A dated news item recording that Lux Partners Limited was established in the Isle of Man is a historical fact, and renaming it would falsify the record. And a sentence asserting that the company is domiciled in the Isle of Man is a claim about a jurisdiction, not a name — an Inc or an LLC is not an Isle of Man company, so swapping the name there would assert something untrue. Co-authored-by: Hanzo Dev <[email protected]>
394 lines
13 KiB
Go
394 lines
13 KiB
Go
// Copyright (C) 2025, Lux Industries Inc All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Package validatormanager provides L1 validator lifecycle management.
|
|
package validatormanager
|
|
|
|
import (
|
|
"context"
|
|
_ "embed"
|
|
"fmt"
|
|
"math/big"
|
|
"strings"
|
|
|
|
"github.com/luxfi/geth/accounts/abi/bind"
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/luxfi/geth/core/types"
|
|
"github.com/luxfi/geth/ethclient"
|
|
luxlog "github.com/luxfi/log"
|
|
blockchainSDK "github.com/luxfi/sdk/blockchain"
|
|
"github.com/luxfi/sdk/contract"
|
|
"github.com/luxfi/sdk/models"
|
|
|
|
luxcrypto "github.com/luxfi/crypto"
|
|
)
|
|
|
|
//go:embed smart_contracts/deployed_validator_messages_bytecode_v2.0.0.txt
|
|
var deployedValidatorMessagesV2_0_0Bytecode []byte
|
|
|
|
func AddValidatorMessagesV2_0_0ContractToAllocations(
|
|
allocs types.GenesisAlloc,
|
|
) {
|
|
deployedValidatorMessagesBytes := common.FromHex(strings.TrimSpace(string(deployedValidatorMessagesV2_0_0Bytecode)))
|
|
allocs[common.Address(luxcrypto.HexToAddress(ValidatorMessagesContractAddress))] = types.Account{
|
|
Balance: big.NewInt(0),
|
|
Code: deployedValidatorMessagesBytes,
|
|
Nonce: 1,
|
|
}
|
|
}
|
|
|
|
func fillValidatorMessagesAddressPlaceholder(contract string) string {
|
|
return strings.ReplaceAll(
|
|
contract,
|
|
"__$fd0c147b4031eef6079b0498cbafa865f0$__",
|
|
ValidatorMessagesContractAddress[2:],
|
|
)
|
|
}
|
|
|
|
//go:embed smart_contracts/deployed_poa_validator_manager_bytecode_v1.0.0.txt
|
|
var deployedPoAValidatorManagerV1_0_0Bytecode []byte
|
|
|
|
func AddPoAValidatorManagerV1_0_0ContractToAllocations(
|
|
allocs types.GenesisAlloc,
|
|
) {
|
|
deployedPoaValidatorManagerString := strings.TrimSpace(string(deployedPoAValidatorManagerV1_0_0Bytecode))
|
|
deployedPoaValidatorManagerString = fillValidatorMessagesAddressPlaceholder(deployedPoaValidatorManagerString)
|
|
deployedPoaValidatorManagerBytes := common.FromHex(deployedPoaValidatorManagerString)
|
|
allocs[common.Address(luxcrypto.HexToAddress(ValidatorContractAddress))] = types.Account{
|
|
Balance: big.NewInt(0),
|
|
Code: deployedPoaValidatorManagerBytes,
|
|
Nonce: 1,
|
|
}
|
|
}
|
|
|
|
//go:embed smart_contracts/deployed_validator_manager_bytecode_v2.0.0.txt
|
|
var deployedValidatorManagerV2_0_0Bytecode []byte
|
|
|
|
func AddValidatorManagerV2_0_0ContractToAllocations(
|
|
allocs types.GenesisAlloc,
|
|
) {
|
|
deployedValidatorManagerString := strings.TrimSpace(string(deployedValidatorManagerV2_0_0Bytecode))
|
|
deployedValidatorManagerString = fillValidatorMessagesAddressPlaceholder(deployedValidatorManagerString)
|
|
deployedValidatorManagerBytes := common.FromHex(deployedValidatorManagerString)
|
|
allocs[common.Address(luxcrypto.HexToAddress(ValidatorContractAddress))] = types.Account{
|
|
Balance: big.NewInt(0),
|
|
Code: deployedValidatorManagerBytes,
|
|
Nonce: 1,
|
|
}
|
|
}
|
|
|
|
//go:embed smart_contracts/validator_manager_bytecode_v2.0.0.txt
|
|
var validatorManagerV2_0_0Bytecode []byte
|
|
|
|
func DeployValidatorManagerV2_0_0Contract(
|
|
rpcURL string,
|
|
privateKey string,
|
|
) (luxcrypto.Address, error) {
|
|
validatorManagerString := strings.TrimSpace(string(validatorManagerV2_0_0Bytecode))
|
|
validatorManagerString = fillValidatorMessagesAddressPlaceholder(validatorManagerString)
|
|
validatorManagerBytes := []byte(validatorManagerString)
|
|
return contract.DeployContract(
|
|
rpcURL,
|
|
privateKey,
|
|
validatorManagerBytes,
|
|
"(uint8)",
|
|
uint8(0),
|
|
)
|
|
}
|
|
|
|
func DeployAndRegisterValidatorManagerV2_0_0Contract(
|
|
rpcURL string,
|
|
privateKey string,
|
|
proxyOwnerPrivateKey string,
|
|
) (luxcrypto.Address, error) {
|
|
validatorManagerAddress, err := DeployValidatorManagerV2_0_0Contract(
|
|
rpcURL,
|
|
privateKey,
|
|
)
|
|
if err != nil {
|
|
return luxcrypto.Address{}, err
|
|
}
|
|
if _, _, err := SetupValidatorProxyImplementation(
|
|
rpcURL,
|
|
proxyOwnerPrivateKey,
|
|
validatorManagerAddress,
|
|
); err != nil {
|
|
return luxcrypto.Address{}, err
|
|
}
|
|
return validatorManagerAddress, nil
|
|
}
|
|
|
|
//go:embed smart_contracts/native_token_staking_manager_bytecode_v1.0.0.txt
|
|
var posValidatorManagerV1_0_0Bytecode []byte
|
|
|
|
func DeployPoSValidatorManagerV1_0_0Contract(
|
|
rpcURL string,
|
|
privateKey string,
|
|
) (luxcrypto.Address, error) {
|
|
posValidatorManagerString := strings.TrimSpace(string(posValidatorManagerV1_0_0Bytecode))
|
|
posValidatorManagerString = fillValidatorMessagesAddressPlaceholder(posValidatorManagerString)
|
|
posValidatorManagerBytes := []byte(posValidatorManagerString)
|
|
return contract.DeployContract(
|
|
rpcURL,
|
|
privateKey,
|
|
posValidatorManagerBytes,
|
|
"(uint8)",
|
|
uint8(0),
|
|
)
|
|
}
|
|
|
|
func DeployAndRegisterPoSValidatorManagerV1_0_0Contract(
|
|
rpcURL string,
|
|
privateKey string,
|
|
proxyOwnerPrivateKey string,
|
|
) (luxcrypto.Address, error) {
|
|
posValidatorManagerAddress, err := DeployPoSValidatorManagerV1_0_0Contract(
|
|
rpcURL,
|
|
privateKey,
|
|
)
|
|
if err != nil {
|
|
return luxcrypto.Address{}, err
|
|
}
|
|
if _, _, err := SetupValidatorProxyImplementation(
|
|
rpcURL,
|
|
proxyOwnerPrivateKey,
|
|
posValidatorManagerAddress,
|
|
); err != nil {
|
|
return luxcrypto.Address{}, err
|
|
}
|
|
return posValidatorManagerAddress, nil
|
|
}
|
|
|
|
//go:embed smart_contracts/native_token_staking_manager_bytecode_v2.0.0.txt
|
|
var posValidatorManagerV2_0_0Bytecode []byte
|
|
|
|
func DeployPoSValidatorManagerV2_0_0Contract(
|
|
rpcURL string,
|
|
privateKey string,
|
|
) (luxcrypto.Address, error) {
|
|
posValidatorManagerString := strings.TrimSpace(string(posValidatorManagerV2_0_0Bytecode))
|
|
posValidatorManagerString = fillValidatorMessagesAddressPlaceholder(posValidatorManagerString)
|
|
posValidatorManagerBytes := []byte(posValidatorManagerString)
|
|
return contract.DeployContract(
|
|
rpcURL,
|
|
privateKey,
|
|
posValidatorManagerBytes,
|
|
"(uint8)",
|
|
uint8(0),
|
|
)
|
|
}
|
|
|
|
func DeployAndRegisterPoSValidatorManagerV2_0_0Contract(
|
|
rpcURL string,
|
|
privateKey string,
|
|
proxyOwnerPrivateKey string,
|
|
) (luxcrypto.Address, error) {
|
|
posValidatorManagerAddress, err := DeployPoSValidatorManagerV2_0_0Contract(
|
|
rpcURL,
|
|
privateKey,
|
|
)
|
|
if err != nil {
|
|
return luxcrypto.Address{}, err
|
|
}
|
|
if _, _, err := SetupSpecializationProxyImplementation(
|
|
rpcURL,
|
|
proxyOwnerPrivateKey,
|
|
posValidatorManagerAddress,
|
|
); err != nil {
|
|
return luxcrypto.Address{}, err
|
|
}
|
|
return posValidatorManagerAddress, nil
|
|
}
|
|
|
|
//go:embed smart_contracts/deployed_transparent_proxy_bytecode.txt
|
|
var deployedTransparentProxyBytecode []byte
|
|
|
|
//go:embed smart_contracts/deployed_proxy_admin_bytecode.txt
|
|
var deployedProxyAdminBytecode []byte
|
|
|
|
func AddValidatorTransparentProxyContractToAllocations(
|
|
allocs types.GenesisAlloc,
|
|
proxyManager string,
|
|
) {
|
|
if _, found := allocs[common.Address(luxcrypto.HexToAddress(proxyManager))]; !found {
|
|
ownerBalance := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1))
|
|
allocs[common.Address(luxcrypto.HexToAddress(proxyManager))] = types.Account{
|
|
Balance: ownerBalance,
|
|
}
|
|
}
|
|
// proxy admin
|
|
deployedProxyAdmin := common.FromHex(strings.TrimSpace(string(deployedProxyAdminBytecode)))
|
|
allocs[common.Address(luxcrypto.HexToAddress(ValidatorProxyAdminContractAddress))] = types.Account{
|
|
Balance: big.NewInt(0),
|
|
Code: deployedProxyAdmin,
|
|
Nonce: 1,
|
|
Storage: map[common.Hash]common.Hash{
|
|
common.HexToHash("0x0"): common.HexToHash(proxyManager),
|
|
},
|
|
}
|
|
|
|
// transparent proxy
|
|
deployedTransparentProxy := common.FromHex(strings.TrimSpace(string(deployedTransparentProxyBytecode)))
|
|
allocs[common.Address(luxcrypto.HexToAddress(ValidatorProxyContractAddress))] = types.Account{
|
|
Balance: big.NewInt(0),
|
|
Code: deployedTransparentProxy,
|
|
Nonce: 1,
|
|
Storage: map[common.Hash]common.Hash{
|
|
common.HexToHash("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"): common.HexToHash(ValidatorContractAddress), // sslot for address of ValidatorManager logic -> bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
|
|
common.HexToHash("0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"): common.HexToHash(ValidatorProxyAdminContractAddress), // sslot for address of ProxyAdmin -> bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
|
|
// we can omit 3rd sslot for _data, as we initialize ValidatorManager after chain is live
|
|
},
|
|
}
|
|
}
|
|
|
|
func AddSpecializationTransparentProxyContractToAllocations(
|
|
allocs types.GenesisAlloc,
|
|
proxyManager string,
|
|
) {
|
|
if _, found := allocs[common.Address(luxcrypto.HexToAddress(proxyManager))]; !found {
|
|
ownerBalance := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1))
|
|
allocs[common.Address(luxcrypto.HexToAddress(proxyManager))] = types.Account{
|
|
Balance: ownerBalance,
|
|
}
|
|
}
|
|
// proxy admin
|
|
deployedProxyAdmin := common.FromHex(strings.TrimSpace(string(deployedProxyAdminBytecode)))
|
|
allocs[common.Address(luxcrypto.HexToAddress(SpecializationProxyAdminContractAddress))] = types.Account{
|
|
Balance: big.NewInt(0),
|
|
Code: deployedProxyAdmin,
|
|
Nonce: 1,
|
|
Storage: map[common.Hash]common.Hash{
|
|
common.HexToHash("0x0"): common.HexToHash(proxyManager),
|
|
},
|
|
}
|
|
|
|
// transparent proxy
|
|
deployedTransparentProxy := common.FromHex(strings.TrimSpace(string(deployedTransparentProxyBytecode)))
|
|
allocs[common.Address(luxcrypto.HexToAddress(SpecializationProxyContractAddress))] = types.Account{
|
|
Balance: big.NewInt(0),
|
|
Code: deployedTransparentProxy,
|
|
Nonce: 1,
|
|
Storage: map[common.Hash]common.Hash{
|
|
common.HexToHash("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"): common.HexToHash(ValidatorContractAddress), // sslot for address of ValidatorManager logic -> bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
|
|
common.HexToHash("0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"): common.HexToHash(SpecializationProxyAdminContractAddress), // sslot for address of ProxyAdmin -> bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
|
|
// we can omit 3rd sslot for _data, as we initialize ValidatorManager after chain is live
|
|
},
|
|
}
|
|
}
|
|
|
|
//go:embed smart_contracts/deployed_example_reward_calculator_bytecode_v2.0.0.txt
|
|
var deployedRewardCalculatorV2_0_0Bytecode []byte
|
|
|
|
func AddRewardCalculatorV2_0_0ToAllocations(
|
|
allocs types.GenesisAlloc,
|
|
rewardBasisPoints uint64,
|
|
) {
|
|
deployedRewardCalculatorBytes := common.FromHex(strings.TrimSpace(string(deployedRewardCalculatorV2_0_0Bytecode)))
|
|
allocs[common.Address(luxcrypto.HexToAddress(RewardCalculatorAddress))] = types.Account{
|
|
Balance: big.NewInt(0),
|
|
Code: deployedRewardCalculatorBytes,
|
|
Nonce: 1,
|
|
Storage: map[common.Hash]common.Hash{
|
|
common.HexToHash("0x0"): common.BigToHash(new(big.Int).SetUint64(rewardBasisPoints)),
|
|
},
|
|
}
|
|
}
|
|
|
|
// SetupPoA sets up PoA manager after a successful execution of
|
|
// ConvertNetworkToL1Tx on P-Chain.
|
|
// Needs the list of validators for that tx,
|
|
// [convertChainValidators], together with an evm [ownerAddress]
|
|
// to set as the owner of the PoA manager.
|
|
func SetupPoA(
|
|
log luxlog.Logger,
|
|
chain blockchainSDK.Net,
|
|
network models.Network,
|
|
privateKey string,
|
|
aggregatorLogger luxlog.Logger,
|
|
validatorManagerAddressStr string,
|
|
v2_0_0 bool,
|
|
signatureAggregatorEndpoint string,
|
|
) error {
|
|
return chain.InitializeProofOfAuthority(
|
|
log,
|
|
network.SDKNetwork(),
|
|
privateKey,
|
|
aggregatorLogger,
|
|
validatorManagerAddressStr,
|
|
v2_0_0,
|
|
signatureAggregatorEndpoint,
|
|
)
|
|
}
|
|
|
|
// SetupPoS sets up PoS manager after a successful execution of
|
|
// ConvertNetworkToL1Tx on P-Chain.
|
|
// Needs the list of validators for that tx,
|
|
// [convertChainValidators], together with an evm [ownerAddress]
|
|
// to set as the owner of the PoS manager.
|
|
func SetupPoS(
|
|
log luxlog.Logger,
|
|
chain blockchainSDK.Net,
|
|
network models.Network,
|
|
privateKey string,
|
|
aggregatorLogger luxlog.Logger,
|
|
posParams PoSParams,
|
|
managerAddress string,
|
|
specializedManagerAddress string,
|
|
managerOwnerPrivateKey string,
|
|
v2_0_0 bool,
|
|
signatureAggregatorEndpoint string,
|
|
) error {
|
|
// Initialize Proof of Stake validator manager
|
|
log.Info("Initializing Proof of Stake validator manager")
|
|
|
|
// Connect to the blockchain RPC
|
|
client, err := ethclient.Dial(chain.RPC)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to connect to RPC: %w", err)
|
|
}
|
|
defer client.Close()
|
|
|
|
// Parse the private key
|
|
pk, err := luxcrypto.HexToECDSA(strings.TrimPrefix(privateKey, "0x"))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse private key: %w", err)
|
|
}
|
|
|
|
// Get the chain ID
|
|
chainID, err := client.ChainID(context.Background())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get chain ID: %w", err)
|
|
}
|
|
|
|
// Create transaction options
|
|
auth, err := bind.NewKeyedTransactorWithChainID(pk, chainID)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create transactor: %w", err)
|
|
}
|
|
_ = auth // Will be used for contract calls
|
|
_ = managerAddress
|
|
_ = specializedManagerAddress
|
|
_ = managerOwnerPrivateKey
|
|
_ = v2_0_0
|
|
|
|
// Initialize the PoS parameters on the validator manager contract
|
|
// This would typically involve calling initialization methods on the contract
|
|
log.Info("Setting PoS parameters",
|
|
luxlog.UserString("minimumStakeAmount", posParams.MinimumStakeAmount.String()),
|
|
luxlog.UserString("maximumStakeAmount", posParams.MaximumStakeAmount.String()),
|
|
luxlog.UserString("minimumStakeDuration", fmt.Sprintf("%d", posParams.MinimumStakeDuration)),
|
|
luxlog.UserString("minimumDelegationFee", fmt.Sprintf("%d", posParams.MinimumDelegationFee)),
|
|
luxlog.UserString("maximumStakeMultiplier", fmt.Sprintf("%d", posParams.MaximumStakeMultiplier)),
|
|
luxlog.UserString("weightToValueFactor", posParams.WeightToValueFactor.String()),
|
|
luxlog.UserString("rewardCalculatorAddress", fmt.Sprintf("%x", posParams.RewardCalculatorAddress)),
|
|
)
|
|
|
|
// Set up signature aggregation if endpoint is provided
|
|
if signatureAggregatorEndpoint != "" {
|
|
log.Info("Configuring signature aggregator", luxlog.UserString("endpoint", signatureAggregatorEndpoint))
|
|
}
|
|
|
|
log.Info("Proof of Stake validator manager initialized successfully")
|
|
return nil
|
|
}
|