Skip to content

Commit 8de2cb9

Browse files
committed
update
1 parent 3d83fc3 commit 8de2cb9

File tree

2 files changed

+104
-38
lines changed

2 files changed

+104
-38
lines changed

cli/transfer.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -295,18 +295,12 @@ var consolidationUtxosCmdCli = &cli.Command{
295295
Usage: "asset id",
296296
Required: true,
297297
},
298-
&cli.IntFlag{
299-
Name: "count,c",
300-
Usage: "consolidation count",
301-
Required: true,
302-
},
303298
},
304299
}
305300

306301
func consolidationUtxosCmd(c *cli.Context) error {
307302
keystore := c.String("keystore")
308303
asset := c.String("asset")
309-
count := c.Int("count")
310304

311305
dat, err := os.ReadFile(keystore)
312306
if err != nil {
@@ -319,12 +313,12 @@ func consolidationUtxosCmd(c *cli.Context) error {
319313
}
320314

321315
log.Println("asset:", asset)
322-
log.Println("count:", count)
323316

324-
str, err := bot.ConsolidationUnspentOutputs(context.Background(), asset, count, &su)
317+
str, count, err := bot.ConsolidationUnspentOutputs(context.Background(), asset, &su)
325318
if err != nil {
319+
log.Println("Consolidation UTXOs failed: ", err, " count:", count)
326320
return err
327321
}
328-
log.Println("Consolidation UTXOs successfully: ", str.TransactionHash)
322+
log.Println("Consolidation UTXOs successfully: ", str.TransactionHash, " count:", count)
329323
return nil
330324
}

transaction.go

Lines changed: 101 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"log"
1111
"math/big"
12+
"slices"
1213
"time"
1314

1415
"filippo.io/edwards25519"
@@ -564,36 +565,107 @@ func RequestGhostRecipientsWithTraceId(ctx context.Context, recipients []*Transa
564565
return gkm, nil
565566
}
566567

567-
func ConsolidationUnspentOutputs(ctx context.Context, assetId string, count int, su *SafeUser) (*SequencerTransactionRequest, error) {
568-
if count <= 0 || count > 256 {
569-
return nil, fmt.Errorf("invalid count %d", count)
570-
}
568+
func ConsolidationUnspentOutputs(ctx context.Context, assetId string, su *SafeUser) (*SequencerTransactionRequest, int, error) {
571569
membersHash := HashMembers([]string{su.UserId})
572-
utxos, err := ListOutputs(ctx, membersHash, 1, assetId, "unspent", 0, count, su)
573-
if err != nil {
574-
return nil, err
575-
}
576-
if len(utxos) <= 1 {
577-
return nil, fmt.Errorf("insufficient unspent outputs %d", len(utxos))
578-
}
579-
if len(utxos) >= 256 {
580-
return nil, fmt.Errorf("too many unspent outputs %d", len(utxos))
581-
}
582-
amount := common.Zero
583-
for _, o := range utxos {
584-
if o.AssetId != assetId {
585-
return nil, fmt.Errorf("unspent outputs with different asset id %s != %s", o.AssetId, assetId)
570+
571+
var lastStr *SequencerTransactionRequest
572+
var pendingTxHashes []string
573+
var consolidatedCount int
574+
575+
for {
576+
utxos, err := ListOutputs(ctx, membersHash, 1, assetId, "unspent", 0, 255, su)
577+
if err != nil {
578+
return nil, consolidatedCount, err
579+
}
580+
if len(utxos) <= 0 {
581+
break
582+
}
583+
if len(utxos) == 1 && len(pendingTxHashes) == 0 {
584+
// no pending transactions, no need to consolidate
585+
break
586+
}
587+
amount := common.Zero
588+
for _, o := range utxos {
589+
if o.AssetId != assetId {
590+
return nil, consolidatedCount, fmt.Errorf("unspent outputs with different asset id %s != %s", o.AssetId, assetId)
591+
}
592+
if o.State != "unspent" {
593+
return nil, consolidatedCount, fmt.Errorf("unspent outputs with different state %s != unspent", o.State)
594+
}
595+
if slices.Contains(pendingTxHashes, o.TransactionHash) {
596+
pendingTxHashes = slices.DeleteFunc(pendingTxHashes, func(s string) bool {
597+
return s == o.TransactionHash
598+
})
599+
} else {
600+
consolidatedCount++
601+
}
602+
amount = amount.Add(common.NewIntegerFromString(o.Amount))
603+
}
604+
trace := UuidNewV4().String()
605+
str, err := SendTransactionWithOutputs(ctx, assetId, []*TransactionRecipient{
606+
{
607+
MixAddress: NewUUIDMixAddress([]string{su.UserId}, 1),
608+
Amount: amount.String(),
609+
},
610+
}, utxos, trace, nil, nil, su)
611+
if err != nil {
612+
return nil, consolidatedCount, fmt.Errorf("error consolidating outputs: %w", err)
586613
}
587-
if o.State != "unspent" {
588-
return nil, fmt.Errorf("unspent outputs with different state %s != unspent", o.State)
614+
lastStr = str
615+
pendingTxHashes = append(pendingTxHashes, str.TransactionHash)
616+
}
617+
618+
// still have pending transactions, wait for them to be confirmed
619+
if len(pendingTxHashes) > 1 {
620+
pendingOutputs := make([]*Output, len(pendingTxHashes))
621+
var completedOutputs int
622+
for {
623+
for i, txHash := range pendingTxHashes {
624+
if pendingOutputs[i] != nil {
625+
continue
626+
}
627+
output, err := GetOutput(ctx, UniqueObjectId(fmt.Sprintf("%s:%d", txHash, 0)), su)
628+
var apiErr Error
629+
if errors.As(err, &apiErr) && apiErr.Code == 404 {
630+
continue
631+
} else if err != nil {
632+
return nil, consolidatedCount, fmt.Errorf("error getting pending output %s: %w", txHash, err)
633+
}
634+
pendingOutputs[i] = output
635+
completedOutputs++
636+
}
637+
if completedOutputs == len(pendingOutputs) {
638+
break
639+
}
640+
time.Sleep(8 * time.Second)
589641
}
590-
amount = amount.Add(common.NewIntegerFromString(o.Amount))
591-
}
592-
trace := UuidNewV4().String()
593-
return SendTransactionWithOutputs(ctx, assetId, []*TransactionRecipient{
594-
{
595-
MixAddress: NewUUIDMixAddress([]string{su.UserId}, 1),
596-
Amount: amount.String(),
597-
},
598-
}, utxos, trace, nil, nil, su)
642+
var amount common.Integer
643+
for _, o := range pendingOutputs {
644+
if o == nil {
645+
return nil, consolidatedCount, fmt.Errorf("pending output is nil")
646+
}
647+
if o.AssetId != assetId {
648+
return nil, consolidatedCount, fmt.Errorf("pending output with different asset id %s != %s", o.AssetId, assetId)
649+
}
650+
if o.State != "unspent" {
651+
return nil, consolidatedCount, fmt.Errorf("pending output with different state %s != unspent", o.State)
652+
}
653+
amount = amount.Add(common.NewIntegerFromString(o.Amount))
654+
}
655+
requestId := UuidNewV4().String()
656+
str, err := SendTransactionWithOutputs(ctx, assetId, []*TransactionRecipient{
657+
{
658+
MixAddress: NewUUIDMixAddress([]string{su.UserId}, 1),
659+
Amount: amount.String(),
660+
},
661+
}, pendingOutputs, requestId, nil, nil, su)
662+
if err != nil {
663+
return nil, consolidatedCount, fmt.Errorf("error consolidating pending outputs: %w", err)
664+
}
665+
lastStr = str
666+
}
667+
if lastStr == nil {
668+
return nil, consolidatedCount, fmt.Errorf("no transaction created during consolidation")
669+
}
670+
return lastStr, consolidatedCount, nil
599671
}

0 commit comments

Comments
 (0)