mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-17 04:04:21 +01:00
* Rename asp > server * Rename pool > round * Consolidate naming for pubkey/prvkey vars and types * Fix * Fix * Fix wasm * Rename congestionTree > vtxoTree * Fix wasm * Rename payment > request * Rename congestionTree > vtxoTree after syncing with master * Fix Send API in SDK * Fix wasm * Fix wasm * Fixes * Fixes after review * Fix * Fix naming * Fix * Fix e2e tests
138 lines
2.6 KiB
Go
138 lines
2.6 KiB
Go
package domain
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"hash"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type TxRequest struct {
|
|
Id string
|
|
Inputs []Vtxo
|
|
Receivers []Receiver
|
|
}
|
|
|
|
func NewTxRequest(inputs []Vtxo) (*TxRequest, error) {
|
|
request := &TxRequest{
|
|
Id: uuid.New().String(),
|
|
Inputs: inputs,
|
|
}
|
|
if err := request.validate(true); err != nil {
|
|
return nil, err
|
|
}
|
|
return request, nil
|
|
}
|
|
|
|
func (r *TxRequest) AddReceivers(receivers []Receiver) (err error) {
|
|
if r.Receivers == nil {
|
|
r.Receivers = make([]Receiver, 0)
|
|
}
|
|
r.Receivers = append(r.Receivers, receivers...)
|
|
defer func() {
|
|
if err != nil {
|
|
r.Receivers = r.Receivers[:len(r.Receivers)-len(receivers)]
|
|
}
|
|
}()
|
|
err = r.validate(false)
|
|
return
|
|
}
|
|
|
|
func (r TxRequest) TotalInputAmount() uint64 {
|
|
tot := uint64(0)
|
|
for _, in := range r.Inputs {
|
|
tot += in.Amount
|
|
}
|
|
return tot
|
|
}
|
|
|
|
func (r TxRequest) TotalOutputAmount() uint64 {
|
|
tot := uint64(0)
|
|
for _, r := range r.Receivers {
|
|
tot += r.Amount
|
|
}
|
|
return tot
|
|
}
|
|
|
|
func (r TxRequest) validate(ignoreOuts bool) error {
|
|
if len(r.Id) <= 0 {
|
|
return fmt.Errorf("missing id")
|
|
}
|
|
if ignoreOuts {
|
|
return nil
|
|
}
|
|
|
|
if len(r.Receivers) <= 0 {
|
|
return fmt.Errorf("missing outputs")
|
|
}
|
|
for _, r := range r.Receivers {
|
|
if len(r.OnchainAddress) <= 0 && len(r.PubKey) <= 0 {
|
|
return fmt.Errorf("missing receiver destination")
|
|
}
|
|
if r.Amount == 0 {
|
|
return fmt.Errorf("missing receiver amount")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type VtxoKey struct {
|
|
Txid string
|
|
VOut uint32
|
|
}
|
|
|
|
func (k VtxoKey) String() string {
|
|
return fmt.Sprintf("%s:%d", k.Txid, k.VOut)
|
|
}
|
|
|
|
func (k VtxoKey) Hash() string {
|
|
calcHash := func(buf []byte, hasher hash.Hash) []byte {
|
|
_, _ = hasher.Write(buf)
|
|
return hasher.Sum(nil)
|
|
}
|
|
|
|
hash160 := func(buf []byte) []byte {
|
|
return calcHash(calcHash(buf, sha256.New()), sha256.New())
|
|
}
|
|
|
|
buf, _ := hex.DecodeString(k.Txid)
|
|
buf = append(buf, byte(k.VOut))
|
|
return hex.EncodeToString(hash160(buf))
|
|
}
|
|
|
|
type Receiver struct {
|
|
Amount uint64
|
|
OnchainAddress string // onchain
|
|
PubKey string // offchain
|
|
}
|
|
|
|
func (r Receiver) IsOnchain() bool {
|
|
return len(r.OnchainAddress) > 0
|
|
}
|
|
|
|
type Vtxo struct {
|
|
VtxoKey
|
|
Amount uint64
|
|
PubKey string
|
|
RoundTxid string
|
|
SpentBy string // round txid or redeem txid
|
|
Spent bool
|
|
Redeemed bool
|
|
Swept bool
|
|
ExpireAt int64
|
|
RedeemTx string // empty if in-round vtxo
|
|
CreatedAt int64
|
|
}
|
|
|
|
func (v Vtxo) TapKey() (*secp256k1.PublicKey, error) {
|
|
pubkeyBytes, err := hex.DecodeString(v.PubKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return schnorr.ParsePubKey(pubkeyBytes)
|
|
}
|