mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-17 12:14:21 +01:00
224 lines
4.7 KiB
Go
224 lines
4.7 KiB
Go
package txbuilder
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
|
|
"github.com/ark-network/ark/common"
|
|
"github.com/ark-network/ark/internal/core/domain"
|
|
"github.com/ark-network/ark/internal/core/ports"
|
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
|
"github.com/vulpemventures/go-elements/network"
|
|
"github.com/vulpemventures/go-elements/psetv2"
|
|
)
|
|
|
|
const (
|
|
connectorAmount = 450
|
|
)
|
|
|
|
type txBuilder struct {
|
|
net *network.Network
|
|
aspPublicKey *secp256k1.PublicKey
|
|
}
|
|
|
|
func toElementsNetwork(net common.Network) *network.Network {
|
|
switch net {
|
|
case common.MainNet:
|
|
return &network.Liquid
|
|
case common.TestNet:
|
|
return &network.Testnet
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func NewTxBuilder(aspPublicKey *secp256k1.PublicKey, net common.Network) ports.TxBuilder {
|
|
return &txBuilder{
|
|
aspPublicKey: aspPublicKey,
|
|
net: toElementsNetwork(net),
|
|
}
|
|
}
|
|
|
|
// BuildCongestionTree implements ports.TxBuilder.
|
|
func (b *txBuilder) BuildCongestionTree(poolTx string, payments []domain.Payment) (congestionTree []string, err error) {
|
|
poolTxID, err := getTxID(poolTx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
receivers := receiversFromPayments(payments)
|
|
|
|
return buildCongestionTree(
|
|
newOutputScriptFactory(b.aspPublicKey, b.net),
|
|
b.net,
|
|
poolTxID,
|
|
receivers,
|
|
)
|
|
}
|
|
|
|
// BuildForfeitTxs implements ports.TxBuilder.
|
|
func (b *txBuilder) BuildForfeitTxs(poolTx string, payments []domain.Payment) (connectors []string, forfeitTxs []string, err error) {
|
|
poolTxID, err := getTxID(poolTx)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
aspScript, err := p2wpkhScript(b.aspPublicKey, b.net)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
numberOfConnectors := numberOfVTXOs(payments)
|
|
|
|
connectors, err = createConnectors(
|
|
poolTxID,
|
|
1,
|
|
psetv2.OutputArgs{
|
|
Asset: b.net.AssetID,
|
|
Amount: connectorAmount,
|
|
Script: aspScript,
|
|
},
|
|
aspScript,
|
|
numberOfConnectors,
|
|
)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
connectorsAsInputs, err := connectorsToInputArgs(connectors)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
forfeitTxs = make([]string, 0)
|
|
for _, payment := range payments {
|
|
for _, vtxo := range payment.Inputs {
|
|
for _, connector := range connectorsAsInputs {
|
|
forfeitTx, err := createForfeitTx(
|
|
connector,
|
|
psetv2.InputArgs{
|
|
Txid: vtxo.Txid,
|
|
TxIndex: vtxo.VOut,
|
|
},
|
|
vtxo.Amount,
|
|
aspScript,
|
|
b.net,
|
|
)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
forfeitTxs = append(forfeitTxs, forfeitTx)
|
|
}
|
|
}
|
|
}
|
|
|
|
return connectors, forfeitTxs, nil
|
|
}
|
|
|
|
// BuildPoolTx implements ports.TxBuilder.
|
|
func (b *txBuilder) BuildPoolTx(wallet ports.WalletService, payments []domain.Payment) (poolTx string, err error) {
|
|
aspScriptBytes, err := p2wpkhScript(b.aspPublicKey, b.net)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
aspScript := hex.EncodeToString(aspScriptBytes)
|
|
|
|
receivers := receiversFromPayments(payments)
|
|
sharedOutputAmount := sumReceivers(receivers)
|
|
|
|
numberOfConnectors := numberOfVTXOs(payments)
|
|
connectorOutputAmount := connectorAmount * numberOfConnectors
|
|
|
|
ctx := context.Background()
|
|
|
|
return wallet.Transaction().Transfer(ctx, []ports.TxOutput{
|
|
newOutput(aspScript, sharedOutputAmount),
|
|
newOutput(aspScript, connectorOutputAmount),
|
|
})
|
|
}
|
|
|
|
func connectorsToInputArgs(connectors []string) ([]psetv2.InputArgs, error) {
|
|
inputs := make([]psetv2.InputArgs, 0, len(connectors)+1)
|
|
for i, psetb64 := range connectors {
|
|
txID, err := getTxID(psetb64)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
input := psetv2.InputArgs{
|
|
Txid: txID,
|
|
TxIndex: 0,
|
|
}
|
|
inputs = append(inputs, input)
|
|
|
|
if i == len(connectors)-1 {
|
|
input := psetv2.InputArgs{
|
|
Txid: txID,
|
|
TxIndex: 1,
|
|
}
|
|
inputs = append(inputs, input)
|
|
}
|
|
}
|
|
return inputs, nil
|
|
}
|
|
|
|
func getTxID(psetBase64 string) (string, error) {
|
|
pset, err := psetv2.NewPsetFromBase64(psetBase64)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
utx, err := pset.UnsignedTx()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return utx.TxHash().String(), nil
|
|
}
|
|
|
|
func numberOfVTXOs(payments []domain.Payment) uint64 {
|
|
var sum uint64
|
|
for _, payment := range payments {
|
|
sum += uint64(len(payment.Inputs))
|
|
}
|
|
return sum
|
|
}
|
|
|
|
func receiversFromPayments(payments []domain.Payment) []domain.Receiver {
|
|
receivers := make([]domain.Receiver, 0)
|
|
for _, payment := range payments {
|
|
receivers = append(receivers, payment.Receivers...)
|
|
}
|
|
return receivers
|
|
}
|
|
|
|
func sumReceivers(receivers []domain.Receiver) uint64 {
|
|
var sum uint64
|
|
for _, r := range receivers {
|
|
sum += r.Amount
|
|
}
|
|
return sum
|
|
}
|
|
|
|
type output struct {
|
|
script string
|
|
amount uint64
|
|
}
|
|
|
|
func newOutput(script string, amount uint64) ports.TxOutput {
|
|
return &output{
|
|
script: script,
|
|
amount: amount,
|
|
}
|
|
}
|
|
|
|
func (o *output) GetAmount() uint64 {
|
|
return o.amount
|
|
}
|
|
|
|
func (o *output) GetScript() string {
|
|
return o.script
|
|
}
|