github.com/decred/dcrlnd@v0.7.6/lnrpc/marshall_utils.go (about) 1 package lnrpc 2 3 import ( 4 "encoding/hex" 5 "errors" 6 fmt "fmt" 7 8 "github.com/decred/dcrd/chaincfg/v3" 9 "github.com/decred/dcrd/dcrutil/v4" 10 "github.com/decred/dcrd/txscript/v4/stdscript" 11 "github.com/decred/dcrlnd/lnwallet" 12 "github.com/decred/dcrlnd/lnwire" 13 ) 14 15 var ( 16 // ErrAtomsMAtomsMutualExclusive is returned when both an atom and an 17 // matom amount are set. 18 ErrAtomMAtomMutualExclusive = errors.New( 19 "atom and matom arguments are mutually exclusive", 20 ) 21 ) 22 23 // CalculateFeeLimit returns the fee limit in millisatoshis. If a percentage 24 // based fee limit has been requested, we'll factor in the ratio provided with 25 // the amount of the payment. 26 func CalculateFeeLimit(feeLimit *FeeLimit, 27 amount lnwire.MilliAtom) lnwire.MilliAtom { 28 29 switch feeLimit.GetLimit().(type) { 30 31 case *FeeLimit_Fixed: 32 return lnwire.NewMAtomsFromAtoms( 33 dcrutil.Amount(feeLimit.GetFixed()), 34 ) 35 36 case *FeeLimit_FixedMAtoms: 37 return lnwire.MilliAtom(feeLimit.GetFixedMAtoms()) 38 39 case *FeeLimit_Percent: 40 return amount * lnwire.MilliAtom(feeLimit.GetPercent()) / 100 41 42 default: 43 // Fall back to a sane default value that is based on the amount 44 // itself. 45 return lnwallet.DefaultRoutingFeeLimitForAmount(amount) 46 } 47 } 48 49 // UnmarshallAmt returns a strong msat type for a atom/matom pair of rpc 50 // fields. 51 func UnmarshallAmt(amtAtom, amtMAtom int64) (lnwire.MilliAtom, error) { 52 if amtAtom != 0 && amtMAtom != 0 { 53 return 0, ErrAtomMAtomMutualExclusive 54 } 55 56 if amtAtom != 0 { 57 return lnwire.NewMAtomsFromAtoms(dcrutil.Amount(amtAtom)), nil 58 } 59 60 return lnwire.MilliAtom(amtMAtom), nil 61 } 62 63 // ParseConfs validates the minimum and maximum confirmation arguments of a 64 // ListUnspent request. 65 func ParseConfs(min, max int32) (int32, int32, error) { 66 switch { 67 // Ensure that the user didn't attempt to specify a negative number of 68 // confirmations, as that isn't possible. 69 case min < 0: 70 return 0, 0, fmt.Errorf("min confirmations must be >= 0") 71 72 // We'll also ensure that the min number of confs is strictly less than 73 // or equal to the max number of confs for sanity. 74 case min > max: 75 return 0, 0, fmt.Errorf("max confirmations must be >= min " + 76 "confirmations") 77 78 default: 79 return min, max, nil 80 } 81 } 82 83 // MarshalUtxos translates a []*lnwallet.Utxo into a []*lnrpc.Utxo. 84 func MarshalUtxos(utxos []*lnwallet.Utxo, activeNetParams *chaincfg.Params) ( 85 []*Utxo, error) { 86 87 // TODO(decred): this needs to come from the utxo itself. 88 const scriptVersion uint16 = 0 89 90 res := make([]*Utxo, 0, len(utxos)) 91 for _, utxo := range utxos { 92 // Translate lnwallet address type to the proper gRPC proto 93 // address type. 94 var addrType AddressType 95 switch utxo.AddressType { 96 97 case lnwallet.WitnessPubKey: 98 addrType = AddressType_WITNESS_PUBKEY_HASH 99 100 case lnwallet.NestedWitnessPubKey: 101 addrType = AddressType_NESTED_PUBKEY_HASH 102 103 case lnwallet.PubKeyHash: 104 addrType = AddressType_PUBKEY_HASH 105 106 case lnwallet.ScriptHash: 107 addrType = AddressType_SCRIPT_HASH 108 109 case lnwallet.UnknownAddressType: 110 continue 111 112 default: 113 return nil, fmt.Errorf("invalid utxo address type") 114 } 115 116 // Now that we know we have a proper mapping to an address, 117 // we'll convert the regular outpoint to an lnrpc variant. 118 outpoint := &OutPoint{ 119 TxidBytes: utxo.OutPoint.Hash[:], 120 TxidStr: utxo.OutPoint.Hash.String(), 121 OutputIndex: utxo.OutPoint.Index, 122 } 123 124 utxoResp := Utxo{ 125 AddressType: addrType, 126 AmountAtoms: int64(utxo.Value), 127 PkScript: hex.EncodeToString(utxo.PkScript), 128 Outpoint: outpoint, 129 Confirmations: utxo.Confirmations, 130 } 131 132 // Finally, we'll attempt to extract the raw address from the 133 // script so we can display a human friendly address to the end 134 // user. 135 _, outAddresses := stdscript.ExtractAddrs( 136 scriptVersion, utxo.PkScript, activeNetParams, 137 ) 138 139 // If we can't properly locate a single address, then this was 140 // an error in our mapping, and we'll return an error back to 141 // the user. 142 if len(outAddresses) != 1 { 143 return nil, fmt.Errorf("an output was unexpectedly " + 144 "multisig") 145 } 146 utxoResp.Address = outAddresses[0].String() 147 148 res = append(res, &utxoResp) 149 } 150 151 return res, nil 152 }