|
16 | 16 | using Neo.Persistence;
|
17 | 17 | using Neo.SmartContract;
|
18 | 18 | using Neo.SmartContract.Native;
|
| 19 | +using Neo.VM; |
19 | 20 | using Neo.Wallets;
|
20 | 21 | using Neo.Wallets.NEP6;
|
21 | 22 | using System;
|
@@ -559,6 +560,88 @@ private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 fro
|
559 | 560 | SignAndSendTx(NeoSystem.StoreView, tx);
|
560 | 561 | }
|
561 | 562 |
|
| 563 | + /// <summary> |
| 564 | + /// Process "cancel" command |
| 565 | + /// </summary> |
| 566 | + /// <param name="txid">conflict txid</param> |
| 567 | + /// <param name="sender">Transaction's sender</param> |
| 568 | + /// <param name="signerAccounts">Signer's accounts</param> |
| 569 | + [ConsoleCommand("cancel", Category = "Wallet Commands")] |
| 570 | + private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] signerAccounts = null) |
| 571 | + { |
| 572 | + TransactionState state = NativeContract.Ledger.GetTransactionState(NeoSystem.StoreView, txid); |
| 573 | + if (state != null) |
| 574 | + { |
| 575 | + ConsoleHelper.Error("This tx is already confirmed, can't be cancelled."); |
| 576 | + return; |
| 577 | + } |
| 578 | + |
| 579 | + var conflict = new TransactionAttribute[] { new Conflicts() { Hash = txid } }; |
| 580 | + Signer[] signers = Array.Empty<Signer>(); |
| 581 | + if (!NoWallet() && sender != null) |
| 582 | + { |
| 583 | + if (signerAccounts == null) |
| 584 | + signerAccounts = new UInt160[1] { sender }; |
| 585 | + else if (signerAccounts.Contains(sender) && signerAccounts[0] != sender) |
| 586 | + { |
| 587 | + var signersList = signerAccounts.ToList(); |
| 588 | + signersList.Remove(sender); |
| 589 | + signerAccounts = signersList.Prepend(sender).ToArray(); |
| 590 | + } |
| 591 | + else if (!signerAccounts.Contains(sender)) |
| 592 | + { |
| 593 | + signerAccounts = signerAccounts.Prepend(sender).ToArray(); |
| 594 | + } |
| 595 | + signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.CalledByEntry }).ToArray(); |
| 596 | + } |
| 597 | + |
| 598 | + Transaction tx = new Transaction |
| 599 | + { |
| 600 | + Signers = signers, |
| 601 | + Attributes = conflict, |
| 602 | + Witnesses = Array.Empty<Witness>(), |
| 603 | + }; |
| 604 | + |
| 605 | + try |
| 606 | + { |
| 607 | + using ScriptBuilder scriptBuilder = new(); |
| 608 | + scriptBuilder.Emit(OpCode.RET); |
| 609 | + tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, scriptBuilder.ToArray(), sender, signers, conflict); |
| 610 | + } |
| 611 | + catch (InvalidOperationException e) |
| 612 | + { |
| 613 | + ConsoleHelper.Error(GetExceptionMessage(e)); |
| 614 | + return; |
| 615 | + } |
| 616 | + |
| 617 | + if (NeoSystem.MemPool.TryGetValue(txid, out Transaction conflictTx)) |
| 618 | + { |
| 619 | + tx.NetworkFee = Math.Max(tx.NetworkFee, conflictTx.NetworkFee) + 1; |
| 620 | + } |
| 621 | + else |
| 622 | + { |
| 623 | + var snapshot = NeoSystem.StoreView; |
| 624 | + AssetDescriptor descriptor = new(snapshot, NeoSystem.Settings, NativeContract.GAS.Hash); |
| 625 | + string extracFee = ReadUserInput("This tx is not in mempool, please input extra fee manually"); |
| 626 | + if (!BigDecimal.TryParse(extracFee, descriptor.Decimals, out BigDecimal decimalExtraFee) || decimalExtraFee.Sign <= 0) |
| 627 | + { |
| 628 | + ConsoleHelper.Error("Incorrect Amount Format"); |
| 629 | + return; |
| 630 | + } |
| 631 | + tx.NetworkFee += (long)decimalExtraFee.Value; |
| 632 | + }; |
| 633 | + |
| 634 | + ConsoleHelper.Info("Network fee: ", |
| 635 | + $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", |
| 636 | + "Total fee: ", |
| 637 | + $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); |
| 638 | + if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) |
| 639 | + { |
| 640 | + return; |
| 641 | + } |
| 642 | + SignAndSendTx(NeoSystem.StoreView, tx); |
| 643 | + } |
| 644 | + |
562 | 645 | /// <summary>
|
563 | 646 | /// Process "show gas" command
|
564 | 647 | /// </summary>
|
|
0 commit comments