117 lines
2.2 KiB
Go
117 lines
2.2 KiB
Go
|
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)
|
||
|
}
|