package eth import ( "crypto/ecdsa" "strings" "custodial/pkg/locker" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil/hdkeychain" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/tyler-smith/go-bip39" ) const MAX_ACCOUNT_INDEX int = 4294967295 type EthAccount struct { privateKey *ecdsa.PrivateKey publicKey *ecdsa.PublicKey address common.Address } func (e *EthAccount) PrivateKey() *ecdsa.PrivateKey { return e.privateKey } func (e *EthAccount) PublicKey() *ecdsa.PublicKey { return e.publicKey } func (e *EthAccount) Address() common.Address { return e.address } const path = "m/44'/60'/0'/0" var master *hdkeychain.ExtendedKey func InitMaster(mnemonic, passphrase string) { if master != nil { return } seed := bip39.NewSeed(strings.TrimSpace(mnemonic), strings.TrimSpace(passphrase)) dpath, err := accounts.ParseDerivationPath(path) if err != nil { panic(err) } key, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams) if err != nil { panic(err) } for _, n := range dpath { key, err = key.Child(n) if err != nil { panic(err) } } master = key privateKey, err := key.ECPrivKey() privateKeyECDSA := privateKey.ToECDSA() if err != nil { panic(err) } publicKey := privateKeyECDSA.Public() _, ok := publicKey.(*ecdsa.PublicKey) if !ok { panic("error casting public key to ECDSA") } } func InitMasterFromPrivateSettings() { mnemonic := locker.GetPrivateEnv("BIP39_MNEMONIC") passphrase := locker.GetPrivateEnv("PASSPHRASE") if mnemonic == "" { panic("BIP39_MNEMONIC is not set") } InitMaster(mnemonic, passphrase) } func DeriveAccount(index int) (*EthAccount, error) { address, err := master.Child(uint32(index)) if err != nil { return nil, err } privateKey, err := address.ECPrivKey() privateKeyECDSA := privateKey.ToECDSA() if err != nil { return nil, err } publicKey, _ := address.ECPubKey() publicKeyECDSA := publicKey.ToECDSA() e := EthAccount{ privateKey: privateKeyECDSA, publicKey: publicKeyECDSA, address: crypto.PubkeyToAddress(*publicKeyECDSA), } return &e, nil } func GetSpender() (*EthAccount, error) { return DeriveAccount(MAX_ACCOUNT_INDEX) }