2019-11-11 18:24:33 +03:00
|
|
|
package lnrpc
|
|
|
|
|
|
|
|
import (
|
2020-05-21 02:12:39 +03:00
|
|
|
"encoding/hex"
|
2019-11-11 18:44:08 +03:00
|
|
|
"errors"
|
2020-05-21 02:12:39 +03:00
|
|
|
fmt "fmt"
|
2019-11-11 18:44:08 +03:00
|
|
|
|
2020-05-21 02:12:39 +03:00
|
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
|
|
"github.com/btcsuite/btcd/txscript"
|
2019-11-11 18:24:33 +03:00
|
|
|
"github.com/btcsuite/btcutil"
|
2020-05-21 02:12:39 +03:00
|
|
|
"github.com/lightningnetwork/lnd/lnwallet"
|
2019-11-11 18:24:33 +03:00
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
|
|
)
|
|
|
|
|
2019-11-11 18:44:08 +03:00
|
|
|
var (
|
|
|
|
// ErrSatMsatMutualExclusive is returned when both a sat and an msat
|
|
|
|
// amount are set.
|
|
|
|
ErrSatMsatMutualExclusive = errors.New(
|
|
|
|
"sat and msat arguments are mutually exclusive",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2019-11-11 18:24:33 +03:00
|
|
|
// CalculateFeeLimit returns the fee limit in millisatoshis. If a percentage
|
|
|
|
// based fee limit has been requested, we'll factor in the ratio provided with
|
|
|
|
// the amount of the payment.
|
|
|
|
func CalculateFeeLimit(feeLimit *FeeLimit,
|
|
|
|
amount lnwire.MilliSatoshi) lnwire.MilliSatoshi {
|
|
|
|
|
|
|
|
switch feeLimit.GetLimit().(type) {
|
|
|
|
|
|
|
|
case *FeeLimit_Fixed:
|
|
|
|
return lnwire.NewMSatFromSatoshis(
|
|
|
|
btcutil.Amount(feeLimit.GetFixed()),
|
|
|
|
)
|
|
|
|
|
2019-11-11 18:44:08 +03:00
|
|
|
case *FeeLimit_FixedMsat:
|
|
|
|
return lnwire.MilliSatoshi(feeLimit.GetFixedMsat())
|
|
|
|
|
2019-11-11 18:24:33 +03:00
|
|
|
case *FeeLimit_Percent:
|
|
|
|
return amount * lnwire.MilliSatoshi(feeLimit.GetPercent()) / 100
|
|
|
|
|
|
|
|
default:
|
|
|
|
// If a fee limit was not specified, we'll use the payment's
|
|
|
|
// amount as an upper bound in order to avoid payment attempts
|
|
|
|
// from incurring fees higher than the payment amount itself.
|
|
|
|
return amount
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 18:44:08 +03:00
|
|
|
|
|
|
|
// UnmarshallAmt returns a strong msat type for a sat/msat pair of rpc fields.
|
|
|
|
func UnmarshallAmt(amtSat, amtMsat int64) (lnwire.MilliSatoshi, error) {
|
|
|
|
if amtSat != 0 && amtMsat != 0 {
|
|
|
|
return 0, ErrSatMsatMutualExclusive
|
|
|
|
}
|
|
|
|
|
|
|
|
if amtSat != 0 {
|
|
|
|
return lnwire.NewMSatFromSatoshis(btcutil.Amount(amtSat)), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return lnwire.MilliSatoshi(amtMsat), nil
|
|
|
|
}
|
2020-05-21 02:12:39 +03:00
|
|
|
|
|
|
|
// ParseConfs validates the minimum and maximum confirmation arguments of a
|
|
|
|
// ListUnspent request.
|
|
|
|
func ParseConfs(min, max int32) (int32, int32, error) {
|
|
|
|
switch {
|
|
|
|
// Ensure that the user didn't attempt to specify a negative number of
|
|
|
|
// confirmations, as that isn't possible.
|
|
|
|
case min < 0:
|
|
|
|
return 0, 0, fmt.Errorf("min confirmations must be >= 0")
|
|
|
|
|
|
|
|
// We'll also ensure that the min number of confs is strictly less than
|
|
|
|
// or equal to the max number of confs for sanity.
|
|
|
|
case min > max:
|
|
|
|
return 0, 0, fmt.Errorf("max confirmations must be >= min " +
|
|
|
|
"confirmations")
|
|
|
|
|
|
|
|
default:
|
|
|
|
return min, max, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalUtxos translates a []*lnwallet.Utxo into a []*lnrpc.Utxo.
|
|
|
|
func MarshalUtxos(utxos []*lnwallet.Utxo, activeNetParams *chaincfg.Params) (
|
|
|
|
[]*Utxo, error) {
|
|
|
|
|
|
|
|
res := make([]*Utxo, 0, len(utxos))
|
|
|
|
for _, utxo := range utxos {
|
|
|
|
// Translate lnwallet address type to the proper gRPC proto
|
|
|
|
// address type.
|
|
|
|
var addrType AddressType
|
|
|
|
switch utxo.AddressType {
|
|
|
|
|
|
|
|
case lnwallet.WitnessPubKey:
|
|
|
|
addrType = AddressType_WITNESS_PUBKEY_HASH
|
|
|
|
|
|
|
|
case lnwallet.NestedWitnessPubKey:
|
|
|
|
addrType = AddressType_NESTED_PUBKEY_HASH
|
|
|
|
|
|
|
|
case lnwallet.UnknownAddressType:
|
|
|
|
continue
|
|
|
|
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("invalid utxo address type")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we know we have a proper mapping to an address,
|
|
|
|
// we'll convert the regular outpoint to an lnrpc variant.
|
|
|
|
outpoint := &OutPoint{
|
|
|
|
TxidBytes: utxo.OutPoint.Hash[:],
|
|
|
|
TxidStr: utxo.OutPoint.Hash.String(),
|
|
|
|
OutputIndex: utxo.OutPoint.Index,
|
|
|
|
}
|
|
|
|
|
|
|
|
utxoResp := Utxo{
|
|
|
|
AddressType: addrType,
|
|
|
|
AmountSat: int64(utxo.Value),
|
|
|
|
PkScript: hex.EncodeToString(utxo.PkScript),
|
|
|
|
Outpoint: outpoint,
|
|
|
|
Confirmations: utxo.Confirmations,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, we'll attempt to extract the raw address from the
|
|
|
|
// script so we can display a human friendly address to the end
|
|
|
|
// user.
|
|
|
|
_, outAddresses, _, err := txscript.ExtractPkScriptAddrs(
|
|
|
|
utxo.PkScript, activeNetParams,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we can't properly locate a single address, then this was
|
|
|
|
// an error in our mapping, and we'll return an error back to
|
|
|
|
// the user.
|
|
|
|
if len(outAddresses) != 1 {
|
|
|
|
return nil, fmt.Errorf("an output was unexpectedly " +
|
|
|
|
"multisig")
|
|
|
|
}
|
|
|
|
utxoResp.Address = outAddresses[0].String()
|
|
|
|
|
|
|
|
res = append(res, &utxoResp)
|
|
|
|
}
|
|
|
|
|
|
|
|
return res, nil
|
|
|
|
}
|