terra/wallet.go

112 lines
2.7 KiB
Go

package terra
import (
"context"
"fmt"
"sync"
"github.com/galacticship/terra/cosmos"
"github.com/galacticship/terra/crypto"
"github.com/pkg/errors"
)
type Wallet struct {
q *Querier
privKey crypto.PrivKey
transactionLock *sync.Mutex
gasAdjustment cosmos.Dec
gasPrice cosmos.DecCoin
}
type WalletOption func(w *Wallet) *Wallet
func WithGasAdjustment(gasAdjustment cosmos.Dec) WalletOption {
return func(w *Wallet) *Wallet {
w.gasAdjustment = gasAdjustment
return w
}
}
func WithGasPrice(gasPrice cosmos.DecCoin) WalletOption {
return func(w *Wallet) *Wallet {
w.gasPrice = gasPrice
return w
}
}
func NewWalletFromMnemonic(querier *Querier, mnemonic string, account uint32, index uint32, options ...WalletOption) (*Wallet, error) {
privKeyBz, err := crypto.DerivePrivKeyBz(mnemonic, crypto.CreateHDPath(account, index))
if err != nil {
return nil, errors.Wrap(err, "deriving private key bytes")
}
privKey, err := crypto.PrivKeyGen(privKeyBz)
if err != nil {
return nil, errors.Wrap(err, "generating private key")
}
return NewWalletFromPrivateKey(querier, privKey, options...), nil
}
func NewWalletFromPrivateKey(querier *Querier, privateKey crypto.PrivKey, options ...WalletOption) *Wallet {
w := &Wallet{
q: querier,
privKey: privateKey,
transactionLock: &sync.Mutex{},
gasAdjustment: cosmos.NewDecFromIntWithPrec(cosmos.NewInt(14), 1),
gasPrice: cosmos.NewDecCoinFromDec("uusd", cosmos.NewDecFromIntWithPrec(cosmos.NewInt(15), 2)),
}
for _, option := range options {
w = option(w)
}
return w
}
func (a Wallet) GasAdjustment() cosmos.Dec {
return a.gasAdjustment
}
func (a Wallet) GasPrice() cosmos.DecCoin {
return a.gasPrice
}
func (a Wallet) Address() cosmos.AccAddress {
return cosmos.AccAddress(a.privKey.PubKey().Address())
}
type WalletState struct {
AccountNumber uint64 `json:"account_number,string"`
Sequence uint64 `json:"sequence,string"`
}
func (a Wallet) State(ctx context.Context) (WalletState, error) {
var response struct {
AccountInfo WalletState `json:"account"`
}
err := a.q.GET(ctx, fmt.Sprintf("cosmos/auth/v1beta1/accounts/%s", a.Address().String()), nil, &response)
if err != nil {
return WalletState{}, errors.Wrap(err, "querying lcd")
}
return response.AccountInfo, nil
}
func (a Wallet) SignTransaction(transaction *Transaction) error {
err := transaction.sign(transaction.signMode, cosmos.SignerData{
AccountNumber: transaction.accountNumber,
ChainID: a.q.ChainId(),
Sequence: transaction.sequence,
}, a.privKey, true)
if err != nil {
return errors.Wrap(err, "signing transaction")
}
return nil
}
func (a Wallet) lock() {
a.transactionLock.Lock()
}
func (a Wallet) unlock() {
a.transactionLock.Unlock()
}