func (c *SimpleCoin) PkScript() []byte {
	return c.txOut().PkScript
}
PkScript returns the outpoint script of the Coin.

This can be used to determine what type of script the Coin uses
and extract standard addresses if possible using
txscript.ExtractPkScriptAddrs for example.
package coinset
import (
	"container/list"
	"errors"
	"sort"
	"github.com/soteria-dag/soterd/chaincfg/chainhash"
	"github.com/soteria-dag/soterd/wire"
	"github.com/soteria-dag/soterd/soterutil"
)
type Coin interface {
	Hash() *chainhash.Hash
	Index() uint32
	Value() soterutil.Amount
	PkScript() []byte
	NumConfs() int64
	ValueAge() int64
}
type Coins interface {
	Coins() []Coin
}
type CoinSet struct {
	coinList      *list.List
	totalValue    soterutil.Amount
	totalValueAge int64
}
var _ Coins = NewCoinSet(nil)
func NewCoinSet(coins []Coin) *CoinSet {
	newCoinSet := &CoinSet{
		coinList:      list.New(),
		totalValue:    0,
		totalValueAge: 0,
	}
	for _, coin := range coins {
		newCoinSet.PushCoin(coin)
	}
	return newCoinSet
}
func (cs *CoinSet) Coins() []Coin {
	coins := make([]Coin, cs.coinList.Len())
	for i, e := 0, cs.coinList.Front(); e != nil; i, e = i+1, e.Next() {
		coins[i] = e.Value.(Coin)
	}
	return coins
}
func (cs *CoinSet) TotalValue() (value soterutil.Amount) {
	return cs.totalValue
}
func (cs *CoinSet) TotalValueAge() (valueAge int64) {
	return cs.totalValueAge
}
func (cs *CoinSet) Num() int {
	return cs.coinList.Len()
}
func (cs *CoinSet) PushCoin(c Coin) {
	cs.coinList.PushBack(c)
	cs.totalValue += c.Value()
	cs.totalValueAge += c.ValueAge()
}
func (cs *CoinSet) PopCoin() Coin {
	back := cs.coinList.Back()
	if back == nil {
		return nil
	}
	return cs.removeElement(back)
}
func (cs *CoinSet) ShiftCoin() Coin {
	front := cs.coinList.Front()
	if front == nil {
		return nil
	}
	return cs.removeElement(front)
}
func (cs *CoinSet) removeElement(e *list.Element) Coin {
	c := e.Value.(Coin)
	cs.coinList.Remove(e)
	cs.totalValue -= c.Value()
	cs.totalValueAge -= c.ValueAge()
	return c
}
func NewMsgTxWithInputCoins(txVersion int32, inputCoins Coins) *wire.MsgTx {
	msgTx := wire.NewMsgTx(txVersion)
	coins := inputCoins.Coins()
	msgTx.TxIn = make([]*wire.TxIn, len(coins))
	for i, coin := range coins {
		msgTx.TxIn[i] = &wire.TxIn{
			PreviousOutPoint: wire.OutPoint{
				Hash:  *coin.Hash(),
				Index: coin.Index(),
			},
			SignatureScript: nil,
			Sequence:        wire.MaxTxInSequenceNum,
		}
	}
	return msgTx
}
var (
	ErrCoinsNoSelectionAvailable = errors.New("no coin selection possible")
)
func satisfiesTargetValue(targetValue, minChange, totalValue soterutil.Amount) bool {
	return (totalValue == targetValue || totalValue >= targetValue+minChange)
}
type CoinSelector interface {
	CoinSelect(targetValue soterutil.Amount, coins []Coin) (Coins, error)
}
type MinIndexCoinSelector struct {
	MaxInputs       int
	MinChangeAmount soterutil.Amount
}
func (s MinIndexCoinSelector) CoinSelect(targetValue soterutil.Amount, coins []Coin) (Coins, error) {
	cs := NewCoinSet(nil)
	for n := 0; n < len(coins) && n < s.MaxInputs; n++ {
		cs.PushCoin(coins[n])
		if satisfiesTargetValue(targetValue, s.MinChangeAmount, cs.TotalValue()) {
			return cs, nil
		}
	}
	return nil, ErrCoinsNoSelectionAvailable
}
type MinNumberCoinSelector struct {
	MaxInputs       int
	MinChangeAmount soterutil.Amount
}
func (s MinNumberCoinSelector) CoinSelect(targetValue soterutil.Amount, coins []Coin) (Coins, error) {
	sortedCoins := make([]Coin, 0, len(coins))
	sortedCoins = append(sortedCoins, coins...)
	sort.Sort(sort.Reverse(byAmount(sortedCoins)))
	return MinIndexCoinSelector(s).CoinSelect(targetValue, sortedCoins)
}
type MaxValueAgeCoinSelector struct {
	MaxInputs       int
	MinChangeAmount soterutil.Amount
}
func (s MaxValueAgeCoinSelector) CoinSelect(targetValue soterutil.Amount, coins []Coin) (Coins, error) {
	sortedCoins := make([]Coin, 0, len(coins))
	sortedCoins = append(sortedCoins, coins...)
	sort.Sort(sort.Reverse(byValueAge(sortedCoins)))
	return MinIndexCoinSelector(s).CoinSelect(targetValue, sortedCoins)
}
type MinPriorityCoinSelector struct {
	MaxInputs              int
	MinChangeAmount        soterutil.Amount
	MinAvgValueAgePerInput int64
}
func (s MinPriorityCoinSelector) CoinSelect(targetValue soterutil.Amount, coins []Coin) (Coins, error) {
	possibleCoins := make([]Coin, 0, len(coins))
	possibleCoins = append(possibleCoins, coins...)
	sort.Sort(byValueAge(possibleCoins))
	cutoffIndex := -1
	for i := 0; i < len(possibleCoins); i++ {
		if possibleCoins[i].ValueAge() >= s.MinAvgValueAgePerInput {
			cutoffIndex = i
			break
		}
	}
	if cutoffIndex < 0 {
		return nil, ErrCoinsNoSelectionAvailable
	}
	for i := cutoffIndex; i < len(possibleCoins); i++ {
		possibleHighCoins := possibleCoins[cutoffIndex : i+1]
		highSelect, err := (&MinNumberCoinSelector{
			MaxInputs:       s.MaxInputs,
			MinChangeAmount: s.MinChangeAmount,
		}).CoinSelect(targetValue, possibleHighCoins)
		if err != nil {
			for numLow := 1; numLow <= cutoffIndex && numLow+(i-cutoffIndex) <= s.MaxInputs; numLow++ {
				allHigh := NewCoinSet(possibleCoins[cutoffIndex : i+1])
				newTargetValue := targetValue - allHigh.TotalValue()
				newMaxInputs := allHigh.Num() + numLow
				if newMaxInputs > numLow {
					newMaxInputs = numLow
				}
				newMinAvgValueAge := ((s.MinAvgValueAgePerInput * int64(allHigh.Num()+numLow)) - allHigh.TotalValueAge()) / int64(numLow)
				lowSelect, err := (&MinPriorityCoinSelector{
					MaxInputs:              newMaxInputs,
					MinChangeAmount:        s.MinChangeAmount,
					MinAvgValueAgePerInput: newMinAvgValueAge,
				}).CoinSelect(newTargetValue, possibleCoins[0:cutoffIndex])
				if err != nil {
					continue
				}
				for _, coin := range lowSelect.Coins() {
					allHigh.PushCoin(coin)
				}
				return allHigh, nil
			}
		} else {
			extendedCoins := NewCoinSet(highSelect.Coins())
			for n := 0; n < cutoffIndex; n++ {
				if extendedCoins.Num() >= s.MaxInputs {
					break
				}
				if possibleCoins[n].ValueAge() == 0 {
					continue
				}
				extendedCoins.PushCoin(possibleCoins[n])
				if extendedCoins.TotalValueAge()/int64(extendedCoins.Num()) < s.MinAvgValueAgePerInput {
					extendedCoins.PopCoin()
					continue
				}
			}
			return extendedCoins, nil
		}
	}
	return nil, ErrCoinsNoSelectionAvailable
}
type byValueAge []Coin
func (a byValueAge) Len() int           { return len(a) }
func (a byValueAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byValueAge) Less(i, j int) bool { return a[i].ValueAge() < a[j].ValueAge() }
type byAmount []Coin
func (a byAmount) Len() int           { return len(a) }
func (a byAmount) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byAmount) Less(i, j int) bool { return a[i].Value() < a[j].Value() }
type SimpleCoin struct {
	Tx         *soterutil.Tx
	TxIndex    uint32
	TxNumConfs int64
}
var _ Coin = &SimpleCoin{}
func (c *SimpleCoin) Hash() *chainhash.Hash {
	return c.Tx.Hash()
}
func (c *SimpleCoin) Index() uint32 {
	return c.TxIndex
}
func (c *SimpleCoin) txOut() *wire.TxOut {
	return c.Tx.MsgTx().TxOut[c.TxIndex]
}
func (c *SimpleCoin) Value() soterutil.Amount {
	return soterutil.Amount(c.txOut().Value)
}