2019-03-06 20:13:50 +00:00
|
|
|
package lndclient
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/btcsuite/btcutil"
|
2019-03-07 02:22:46 +00:00
|
|
|
"github.com/lightninglabs/loop/swap"
|
2019-03-06 20:13:50 +00:00
|
|
|
"github.com/lightningnetwork/lnd/keychain"
|
|
|
|
"github.com/lightningnetwork/lnd/lnrpc/signrpc"
|
|
|
|
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
2019-11-16 00:16:30 +00:00
|
|
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
2019-03-06 20:13:50 +00:00
|
|
|
"google.golang.org/grpc"
|
|
|
|
)
|
|
|
|
|
|
|
|
// WalletKitClient exposes wallet functionality.
|
|
|
|
type WalletKitClient interface {
|
|
|
|
DeriveNextKey(ctx context.Context, family int32) (
|
|
|
|
*keychain.KeyDescriptor, error)
|
|
|
|
|
|
|
|
DeriveKey(ctx context.Context, locator *keychain.KeyLocator) (
|
|
|
|
*keychain.KeyDescriptor, error)
|
|
|
|
|
|
|
|
NextAddr(ctx context.Context) (btcutil.Address, error)
|
|
|
|
|
|
|
|
PublishTransaction(ctx context.Context, tx *wire.MsgTx) error
|
|
|
|
|
|
|
|
SendOutputs(ctx context.Context, outputs []*wire.TxOut,
|
2019-11-16 00:16:30 +00:00
|
|
|
feeRate chainfee.SatPerKWeight) (*wire.MsgTx, error)
|
2019-03-06 20:13:50 +00:00
|
|
|
|
2019-11-16 00:16:30 +00:00
|
|
|
EstimateFee(ctx context.Context, confTarget int32) (chainfee.SatPerKWeight,
|
2019-03-06 20:13:50 +00:00
|
|
|
error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type walletKitClient struct {
|
2019-04-17 02:17:19 +00:00
|
|
|
client walletrpc.WalletKitClient
|
|
|
|
walletKitMac serializedMacaroon
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 02:17:19 +00:00
|
|
|
func newWalletKitClient(conn *grpc.ClientConn,
|
|
|
|
walletKitMac serializedMacaroon) *walletKitClient {
|
|
|
|
|
2019-03-06 20:13:50 +00:00
|
|
|
return &walletKitClient{
|
2019-04-17 02:17:19 +00:00
|
|
|
client: walletrpc.NewWalletKitClient(conn),
|
|
|
|
walletKitMac: walletKitMac,
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *walletKitClient) DeriveNextKey(ctx context.Context, family int32) (
|
|
|
|
*keychain.KeyDescriptor, error) {
|
|
|
|
|
|
|
|
rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2019-04-17 02:17:19 +00:00
|
|
|
rpcCtx = m.walletKitMac.WithMacaroonAuth(rpcCtx)
|
2019-03-06 20:13:50 +00:00
|
|
|
resp, err := m.client.DeriveNextKey(rpcCtx, &walletrpc.KeyReq{
|
|
|
|
KeyFamily: family,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
key, err := btcec.ParsePubKey(resp.RawKeyBytes, btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &keychain.KeyDescriptor{
|
|
|
|
KeyLocator: keychain.KeyLocator{
|
|
|
|
Family: keychain.KeyFamily(resp.KeyLoc.KeyFamily),
|
|
|
|
Index: uint32(resp.KeyLoc.KeyIndex),
|
|
|
|
},
|
|
|
|
PubKey: key,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *walletKitClient) DeriveKey(ctx context.Context, in *keychain.KeyLocator) (
|
|
|
|
*keychain.KeyDescriptor, error) {
|
|
|
|
|
|
|
|
rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2019-04-17 02:17:19 +00:00
|
|
|
rpcCtx = m.walletKitMac.WithMacaroonAuth(rpcCtx)
|
2019-03-06 20:13:50 +00:00
|
|
|
resp, err := m.client.DeriveKey(rpcCtx, &signrpc.KeyLocator{
|
|
|
|
KeyFamily: int32(in.Family),
|
|
|
|
KeyIndex: int32(in.Index),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
key, err := btcec.ParsePubKey(resp.RawKeyBytes, btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &keychain.KeyDescriptor{
|
|
|
|
KeyLocator: *in,
|
|
|
|
PubKey: key,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *walletKitClient) NextAddr(ctx context.Context) (
|
|
|
|
btcutil.Address, error) {
|
|
|
|
|
|
|
|
rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2019-04-17 02:17:19 +00:00
|
|
|
rpcCtx = m.walletKitMac.WithMacaroonAuth(rpcCtx)
|
2019-03-06 20:13:50 +00:00
|
|
|
resp, err := m.client.NextAddr(rpcCtx, &walletrpc.AddrRequest{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := btcutil.DecodeAddress(resp.Addr, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *walletKitClient) PublishTransaction(ctx context.Context,
|
|
|
|
tx *wire.MsgTx) error {
|
|
|
|
|
2019-03-07 02:22:46 +00:00
|
|
|
txHex, err := swap.EncodeTx(tx)
|
2019-03-06 20:13:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2019-04-17 02:17:19 +00:00
|
|
|
rpcCtx = m.walletKitMac.WithMacaroonAuth(rpcCtx)
|
2019-03-06 20:13:50 +00:00
|
|
|
_, err = m.client.PublishTransaction(rpcCtx, &walletrpc.Transaction{
|
|
|
|
TxHex: txHex,
|
|
|
|
})
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *walletKitClient) SendOutputs(ctx context.Context,
|
2019-11-16 00:16:30 +00:00
|
|
|
outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight) (
|
2019-03-06 20:13:50 +00:00
|
|
|
*wire.MsgTx, error) {
|
|
|
|
|
|
|
|
rpcOutputs := make([]*signrpc.TxOut, len(outputs))
|
|
|
|
for i, output := range outputs {
|
|
|
|
rpcOutputs[i] = &signrpc.TxOut{
|
|
|
|
PkScript: output.PkScript,
|
|
|
|
Value: output.Value,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2019-04-17 02:17:19 +00:00
|
|
|
rpcCtx = m.walletKitMac.WithMacaroonAuth(rpcCtx)
|
2019-03-06 20:13:50 +00:00
|
|
|
resp, err := m.client.SendOutputs(rpcCtx, &walletrpc.SendOutputsRequest{
|
|
|
|
Outputs: rpcOutputs,
|
|
|
|
SatPerKw: int64(feeRate),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-03-07 02:22:46 +00:00
|
|
|
tx, err := swap.DecodeTx(resp.RawTx)
|
2019-03-06 20:13:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *walletKitClient) EstimateFee(ctx context.Context, confTarget int32) (
|
2019-11-16 00:16:30 +00:00
|
|
|
chainfee.SatPerKWeight, error) {
|
2019-03-06 20:13:50 +00:00
|
|
|
|
|
|
|
rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2019-04-17 02:17:19 +00:00
|
|
|
rpcCtx = m.walletKitMac.WithMacaroonAuth(rpcCtx)
|
2019-03-06 20:13:50 +00:00
|
|
|
resp, err := m.client.EstimateFee(rpcCtx, &walletrpc.EstimateFeeRequest{
|
|
|
|
ConfTarget: int32(confTarget),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2019-11-16 00:16:30 +00:00
|
|
|
return chainfee.SatPerKWeight(resp.SatPerKw), nil
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|