CI/CD / render (push) Waiting to run
The primary-network chains answer to either case; one spelling beats two. /v1/chain/c/rpc, /v1/chain/p, /v1/chain/x across the estate. Co-authored-by: Hanzo AI <[email protected]>
196 lines
6.0 KiB
Go
196 lines
6.0 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/luxfi/geth/common"
|
|
)
|
|
|
|
// ChainConfig holds the configuration for a single EVM chain.
|
|
type ChainConfig struct {
|
|
Name string
|
|
ChainID *big.Int
|
|
RPC string
|
|
|
|
// Token addresses (may differ per chain — C-chain has unique nonces)
|
|
WLUX common.Address
|
|
LETH common.Address
|
|
LBTC common.Address
|
|
LUSDC common.Address
|
|
|
|
// AMM contracts
|
|
AMMV2Router common.Address
|
|
AMMV2Factory common.Address
|
|
|
|
// Whether AMM swaps work on this chain (app chain EVM may lack MCOPY)
|
|
SwapsEnabled bool
|
|
}
|
|
|
|
// Config holds all bot configuration loaded from environment variables.
|
|
type Config struct {
|
|
Mnemonic string
|
|
|
|
// Chains to operate on
|
|
Chains []ChainConfig
|
|
|
|
// Trading parameters
|
|
TradeIntervalMinSec int
|
|
TradeIntervalMaxSec int
|
|
TradeAmountMinETH float64
|
|
TradeAmountMaxETH float64
|
|
NumWallets int
|
|
|
|
// Wallet indices to use (start..start+NumWallets-1)
|
|
WalletStartIndex int
|
|
}
|
|
|
|
func envOrDefault(key, def string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return def
|
|
}
|
|
|
|
func envIntOrDefault(key string, def int) int {
|
|
if v := os.Getenv(key); v != "" {
|
|
n, err := strconv.Atoi(v)
|
|
if err == nil {
|
|
return n
|
|
}
|
|
}
|
|
return def
|
|
}
|
|
|
|
func envFloatOrDefault(key string, def float64) float64 {
|
|
if v := os.Getenv(key); v != "" {
|
|
f, err := strconv.ParseFloat(v, 64)
|
|
if err == nil {
|
|
return f
|
|
}
|
|
}
|
|
return def
|
|
}
|
|
|
|
// App-chain shared addresses (deployer had nonce=0 on each fresh chain)
|
|
var appChainTokens = struct {
|
|
WLUX, LETH, LBTC, LUSDC common.Address
|
|
AMMV2Router, AMMV2Factory common.Address
|
|
}{
|
|
WLUX: common.HexToAddress("0x548f54dfb32ea6ce4fa3515236696cf3d1b7d26a"),
|
|
LETH: common.HexToAddress("0xe0f7e9a0cb1688cca453995fd6e19ae4fbd9cbfd"),
|
|
LBTC: common.HexToAddress("0x7d7cc8d05bb0f38d80b5ce44b4b069a6fb769468"),
|
|
LUSDC: common.HexToAddress("0xc5e4a6f54be469551a342872c1ab83ab46f61b22"),
|
|
AMMV2Factory: common.HexToAddress("0x84cf0a13db1be8e1f0676405cfcbc8b09692fd1c"),
|
|
AMMV2Router: common.HexToAddress("0x2382f7a49fa48e1f91bec466c32e1d7f13ec8206"),
|
|
}
|
|
|
|
// allChains returns all supported chain configurations.
|
|
// C-chain addresses are from the user-provided contract addresses.
|
|
// App chains use the shared deployed addresses from e2e-exchange.py.
|
|
func allChains() map[string]ChainConfig {
|
|
return map[string]ChainConfig{
|
|
"lux": {
|
|
Name: "Lux C-Chain",
|
|
ChainID: big.NewInt(96369),
|
|
RPC: envOrDefault("RPC_LUX", "https://api.lux.network/mainnet/v1/chain/c/rpc"),
|
|
WLUX: common.HexToAddress("0x3C18bB6B17eb3F0879d4653e0120a531aF4d86E3"),
|
|
LETH: common.HexToAddress("0x5a88986958ea76Dd043f834542724F081cA1443B"),
|
|
LBTC: common.HexToAddress("0x8a3fad1c7FB94461621351aa6A983B6f814F039c"),
|
|
LUSDC: common.HexToAddress("0x57f9E717dc080a6A76fB6F77BecA8C9C1D266B96"),
|
|
AMMV2Factory: common.HexToAddress("0xb06B31521Afc434F87Fe4852c98FC15A26c92aE8"),
|
|
AMMV2Router: common.HexToAddress("0x6A1a32BF731d504122EA318cE7Bd8D92b2284C0d"),
|
|
SwapsEnabled: true, // C-chain supports Cancun opcodes
|
|
},
|
|
"zoo": {
|
|
Name: "Zoo Chain",
|
|
ChainID: big.NewInt(200200),
|
|
RPC: envOrDefault("RPC_ZOO", "https://api.lux.network/mainnet/v1/chain/Z/rpc"),
|
|
WLUX: appChainTokens.WLUX,
|
|
LETH: appChainTokens.LETH,
|
|
LBTC: appChainTokens.LBTC,
|
|
LUSDC: appChainTokens.LUSDC,
|
|
AMMV2Factory: appChainTokens.AMMV2Factory,
|
|
AMMV2Router: appChainTokens.AMMV2Router,
|
|
SwapsEnabled: false, // MCOPY opcode not supported
|
|
},
|
|
"hanzo": {
|
|
Name: "Hanzo Chain",
|
|
ChainID: big.NewInt(36963),
|
|
RPC: envOrDefault("RPC_HANZO", "https://api.lux.network/mainnet/v1/chain/H/rpc"),
|
|
WLUX: appChainTokens.WLUX,
|
|
LETH: appChainTokens.LETH,
|
|
LBTC: appChainTokens.LBTC,
|
|
LUSDC: appChainTokens.LUSDC,
|
|
AMMV2Factory: appChainTokens.AMMV2Factory,
|
|
AMMV2Router: appChainTokens.AMMV2Router,
|
|
SwapsEnabled: false,
|
|
},
|
|
"spc": {
|
|
Name: "SPC Chain",
|
|
ChainID: big.NewInt(36911),
|
|
RPC: envOrDefault("RPC_SPC", "https://api.lux.network/mainnet/v1/chain/S/rpc"),
|
|
WLUX: appChainTokens.WLUX,
|
|
LETH: appChainTokens.LETH,
|
|
LBTC: appChainTokens.LBTC,
|
|
LUSDC: appChainTokens.LUSDC,
|
|
AMMV2Factory: appChainTokens.AMMV2Factory,
|
|
AMMV2Router: appChainTokens.AMMV2Router,
|
|
SwapsEnabled: false,
|
|
},
|
|
"pars": {
|
|
Name: "Pars Chain",
|
|
ChainID: big.NewInt(494949),
|
|
RPC: envOrDefault("RPC_PARS", "https://api.lux.network/mainnet/v1/chain/T/rpc"),
|
|
WLUX: appChainTokens.WLUX,
|
|
LETH: appChainTokens.LETH,
|
|
LBTC: appChainTokens.LBTC,
|
|
LUSDC: appChainTokens.LUSDC,
|
|
AMMV2Factory: appChainTokens.AMMV2Factory,
|
|
AMMV2Router: appChainTokens.AMMV2Router,
|
|
SwapsEnabled: false,
|
|
},
|
|
}
|
|
}
|
|
|
|
// LoadConfig reads configuration from environment variables.
|
|
func LoadConfig() (*Config, error) {
|
|
mnemonic := os.Getenv("MNEMONIC")
|
|
if mnemonic == "" {
|
|
return nil, fmt.Errorf("MNEMONIC environment variable is required")
|
|
}
|
|
|
|
cfg := &Config{
|
|
Mnemonic: mnemonic,
|
|
TradeIntervalMinSec: envIntOrDefault("TRADE_INTERVAL_MIN", 30),
|
|
TradeIntervalMaxSec: envIntOrDefault("TRADE_INTERVAL_MAX", 300),
|
|
TradeAmountMinETH: envFloatOrDefault("TRADE_AMOUNT_MIN", 0.001),
|
|
TradeAmountMaxETH: envFloatOrDefault("TRADE_AMOUNT_MAX", 0.1),
|
|
NumWallets: envIntOrDefault("NUM_WALLETS", 10),
|
|
WalletStartIndex: envIntOrDefault("WALLET_START_INDEX", 2),
|
|
}
|
|
|
|
// Parse CHAINS env var to select which chains to operate on
|
|
chainsEnv := envOrDefault("CHAINS", "lux,zoo,hanzo,spc,pars")
|
|
chainNames := strings.Split(chainsEnv, ",")
|
|
|
|
all := allChains()
|
|
for _, name := range chainNames {
|
|
name = strings.TrimSpace(strings.ToLower(name))
|
|
if cc, ok := all[name]; ok {
|
|
cfg.Chains = append(cfg.Chains, cc)
|
|
} else {
|
|
return nil, fmt.Errorf("unknown chain: %s (valid: lux,zoo,hanzo,spc,pars)", name)
|
|
}
|
|
}
|
|
|
|
if len(cfg.Chains) == 0 {
|
|
return nil, fmt.Errorf("no chains configured")
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|