Skip to content
This repository has been archived by the owner on Nov 30, 2020. It is now read-only.

Safe tx resubmit #47

Merged
merged 1 commit into from
Dec 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion controllers/login.controller.es6
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Intent} from "interstellar-core";
import {Controller, Inject} from "interstellar-core";
import {Keypair} from 'stellar-base';
import {Keypair} from 'stellar-sdk';
import {Alert, AlertGroup} from 'interstellar-ui-messages';
import StellarLedger from 'stellar-ledger-api';

Expand Down
79 changes: 55 additions & 24 deletions controllers/send-widget.controller.es6
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import _ from 'lodash';
import BigNumber from 'bignumber.js';
import {Widget, Inject, Intent} from 'interstellar-core';
import {Alert, AlertGroup} from 'interstellar-ui-messages';
import {Account, Asset, Keypair, Memo, Operation, TransactionBuilder, xdr} from 'stellar-base';
import {Account, Asset, Keypair, Memo, Operation, Transaction, TransactionBuilder, xdr} from 'stellar-sdk';
import {FederationServer} from 'stellar-sdk';
import BasicClientError from '../errors';
import StellarLedger from 'stellar-ledger-api';
Expand Down Expand Up @@ -30,6 +30,8 @@ export default class SendWidgetController {
this.stellarAddress = null;
// Resolved destination (accountId/address)
this.destination = null;
// XDR of the last transaction submitted to horizon. Will be helpful resubmit is needed.
this.lastTransactionXDR = null;

this.$scope.$watch('widget.memoType', type => {
switch (type) {
Expand Down Expand Up @@ -177,6 +179,8 @@ export default class SendWidgetController {
}

this.sending = true;
this.ledgerError = null;

this.addressAlertGroup.clear();
this.amountAlertGroup.clear();
this.memoAlertGroup.clear();
Expand Down Expand Up @@ -336,8 +340,22 @@ export default class SendWidgetController {
});
}

_submitTransaction(operation) {
resubmitTransaction() {
if (this.lastTransactionXDR === null) {
return;
}

this.showView(null, 'sendWaiting');

var transaction = new Transaction(this.lastTransactionXDR);

return this.Server.submitTransaction(transaction)
.then(this._submitOnSuccess.bind(this))
.catch(this._submitOnFailure.bind(this))
.finally(this._submitFinally.bind(this));
}

_submitTransaction(operation) {
return this.Sessions.loadDefaultAccount()
.then(() => {
let memo = Memo.none();
Expand Down Expand Up @@ -372,35 +390,48 @@ export default class SendWidgetController {
let hint = keyPair.signatureHint();
let decorated = new xdr.DecoratedSignature({hint, signature});
transaction.signatures.push(decorated);
return this.Server.submitTransaction(transaction);
}).catch(e => {
this.ledgerError = e;
throw e;
});
} else {
transaction.sign(Keypair.fromSeed(this.session.getSecret()));
return this.Server.submitTransaction(transaction);
}
})
.then(() => {
this.success = true;
this.destinationAddress = null;
this.destination = null;
this.amount = null;
this.memo = false;
this.$rootScope.$broadcast('account-viewer.transaction-success');
})
.catch(e => {
this.success = false;
if (this.ledgerError !== null) {
this.outcomeMessage = this.ledgerError;
} else {
this.outcomeMessage = JSON.stringify(e, null, ' ');
}

this.lastTransactionXDR = transaction.toEnvelope().toXDR().toString("base64");
return this.Server.submitTransaction(transaction);
})
.finally(() => {
this.showView(null, 'sendOutcome');
this.$scope.$apply()
});
.then(this._submitOnSuccess.bind(this))
.catch(this._submitOnFailure.bind(this))
.finally(this._submitFinally.bind(this));
}

_submitOnSuccess() {
this.success = true;
this.destinationAddress = null;
this.destination = null;
this.amount = null;
this.memo = false;
this.lastTransactionXDR = null;
this.$rootScope.$broadcast('account-viewer.transaction-success');
}

_submitOnFailure(e) {
this.success = false;
this.needsResubmit = false;

if (this.ledgerError !== null) {
this.outcomeMessage = this.ledgerError;
} else {
if (e.title != "Transaction Failed" && e.title != "Transaction Malformed") {
this.needsResubmit = true;
}
this.outcomeMessage = JSON.stringify(e, null, ' ');
}
}

_submitFinally() {
this.showView(null, 'sendOutcome');
this.$scope.$apply()
}
}
12 changes: 10 additions & 2 deletions templates/send-widget.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,17 @@ <h2 class="sendPane__title">Send lumens</h2>
<div ng-if="!widget.success">
<p class="sendOutcome__label">Transaction failed</p>

<pre class="sendOutcome__code"><code>{{widget.outcomeMessage}}</code></pre>
<p class="" ng-if="widget.needsResubmit">
<strong>Warning</strong> We submitted your transaction to the network but because of the network conditions we are
not certain about it's status: it could either succeed or fail. Instead of recreating the transaction you should use
the button below to safely resubmit the transaction:<br />
<br />
<button class="s-button sendConfirm__submit" ng-click="widget.resubmitTransaction()">Resubmit transaction</button>
</p>

<pre class="sendOutcome__code" ng-if="widget.outcomeMessage"><code>{{widget.outcomeMessage}}</code></pre>
</div>

<button class="s-button sendOutcome__return" ng-click="widget.showView($event, 'sendSetup')">Send another transaction</button>
<button class="s-button sendOutcome__return" ng-if="widget.success || !widget.needsResubmit" ng-click="widget.showView($event, 'sendSetup')">Send another transaction</button>
</div>
</div>