You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
3.9 KiB
146 lines
3.9 KiB
package lnrpc |
|
|
|
import ( |
|
"encoding/hex" |
|
"errors" |
|
fmt "fmt" |
|
|
|
"github.com/btcsuite/btcd/chaincfg" |
|
"github.com/btcsuite/btcd/txscript" |
|
"github.com/btcsuite/btcutil" |
|
"github.com/lightningnetwork/lnd/lnwallet" |
|
"github.com/lightningnetwork/lnd/lnwire" |
|
) |
|
|
|
var ( |
|
// ErrSatMsatMutualExclusive is returned when both a sat and an msat |
|
// amount are set. |
|
ErrSatMsatMutualExclusive = errors.New( |
|
"sat and msat arguments are mutually exclusive", |
|
) |
|
) |
|
|
|
// 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()), |
|
) |
|
|
|
case *FeeLimit_FixedMsat: |
|
return lnwire.MilliSatoshi(feeLimit.GetFixedMsat()) |
|
|
|
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 |
|
} |
|
} |
|
|
|
// 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 |
|
} |
|
|
|
// 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 |
|
}
|
|
|