Skip to content

Commit

Permalink
feat(assets): add asset reissue
Browse files Browse the repository at this point in the history
Added reissue dialog and confirmation.
Added reissue possibility checking to enable/disable reissue button
  • Loading branch information
beregovoy68 committed Nov 16, 2016
1 parent b57c154 commit 9c98c0f
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 16 deletions.
1 change: 1 addition & 0 deletions Gruntfile.js
Expand Up @@ -157,6 +157,7 @@ module.exports = function (grunt) {
'src/js/portfolio/asset.list.controller.js',
'src/js/portfolio/asset.transfer.controller.js',
'src/js/portfolio/asset.details.controller.js',
'src/js/portfolio/asset.reissue.controller.js',
'src/js/portfolio/asset.filter.js',

'src/js/**/*.spec.js'
Expand Down
64 changes: 61 additions & 3 deletions src/index.html
Expand Up @@ -462,7 +462,7 @@ <h1>PORTFOLIO</h1>
<td>{{tx.balance}}</td>
<td>
<button ng-click="assetList.assetTransfer(tx.id)">Transfer</button><span class="divider-2"></span>
<button>Reissue</button><span class="divider-2"></span>
<button ng-enable="tx.formatted.canReissue" ng-click="assetList.assetReissue(tx.id)">Reissue</button><span class="divider-2"></span>
<button ng-click="assetList.assetDetails(tx.id)">Details</button>
</td>
</tr>
Expand Down Expand Up @@ -509,8 +509,8 @@ <h2>ASSET DETAILS</h2>
</table>
</div>
</div>
<div ng-controller="assetTransferController as transfer">
<div id="transfer-asset-dialog" waves-dialog ok-button-caption="TRANSFER" on-dialog-ok="transfer.submitTransfer()">
<div class="noDisp" ng-controller="assetTransferController as transfer">
<div id="asset-transfer-dialog" waves-dialog ok-button-caption="TRANSFER" on-dialog-ok="transfer.submitTransfer()">
<form id="transfer-asset-form" name="transferAssetForm" novalidate ng-validate="transfer.validationOptions">
<h2>ASSET TRANSFER</h2>
<div class="balanceAmt">
Expand Down Expand Up @@ -566,6 +566,63 @@ <h2>ASSET TRANSFER</h2>
<p>Please <span class="fontBold"> CONFIRM </span>to execute or <span class="fontBold"> CANCEL </span> to discard.</p>
</div>
</div>
<div class="noDisp" ng-controller="assetReissueController as reissue">
<div id="asset-reissue-dialog" waves-dialog ok-button-caption="REISSUE" ok-button-enabled="!reissue.confirm.pendingReissue" on-dialog-ok="reissue.submitReissue()">
<form id="asset-reissue-form" name="assetReissueForm" novalidate ng-validate="reissue.validationOptions">
<h2>ASSET REISSUE</h2>
<div class="balanceAmt">
<p>Total tokens issued: </p><span class="balancewaves">{{reissue.totalTokens}}</span>
</div>
<table>
<thead>
<tr>
<th>DESCRIPTION</th>
<th>INPUT</th>
</tr>
</thead>
<tbody>
<tr>
<td>Asset identifier</td>
<td>{{reissue.assetId}}</td>
</tr>
<tr>
<td>Asset name</td>
<td>{{reissue.assetName}}</td>
</tr>

<tr>
<td>Additional amount</td>
<td>
<div class="form-field">
<input class="wInput form-control" name="assetAmount" type="text" placeholder="Amount" ng-model="reissue.amount" />
</div>
</td>
</tr>
<tr>
<td>Reissue enabled</td>
<td>
<div class="form-field">
<input class="wInput form-control" name="assetReissue" type="checkbox" ng-model="reissue.reissuable" />
</div>
</td>
</tr>
<tr>
<td>Fee</td>
<td>{{reissue.fee.formatAmount(true)}}</td>
</tr>
</tbody>
</table>
</form>
</div>
<div id="asset-reissue-confirm-dialog" waves-dialog ok-button-caption="CONFIRM" ok-button-enabled="!reissue.confirm.reissuePending" on-dialog-ok="reissue.broadcastTransaction()">
<p>You are issuing additional amount of <span class="confirmation-value">{{reissue.confirm.amount.value}}</span> tokens <br/>
to the asset <span class="confirmation-value">{{reissue.confirm.amount.currency}}</span>
with <span class="confirmation-value">{{reissue.confirm.fee.value}}</span>
<span class="confirmation-value">{{reissue.confirm.fee.currency}}</span> fee
</p>
<p>Please <span class="fontBold"> CONFIRM </span>to execute or <span class="fontBold"> CANCEL </span> to discard.</p>
</div>
</div>
</div>
</div>
<!-- / PORTFOLIO TAB -->
Expand Down Expand Up @@ -865,6 +922,7 @@ <h2>LATEST BLOCKS INFORMATION</h2>
<script src="js/portfolio/asset.list.controller.js"></script>
<script src="js/portfolio/asset.transfer.controller.js"></script>
<script src="js/portfolio/asset.details.controller.js"></script>
<script src="js/portfolio/asset.reissue.controller.js"></script>
<script src="js/portfolio/asset.filter.js"></script>

<script src="js/style.js"></script>
Expand Down
8 changes: 5 additions & 3 deletions src/js/portfolio/asset.details.controller.js
@@ -1,7 +1,7 @@
(function () {
'use strict';

function WavesAssetDetailsController($scope, events, applicationContext) {
function WavesAssetDetailsController($scope, events, applicationContext, dialogService) {
var details = this;

function transformAddress(address) {
Expand All @@ -17,7 +17,7 @@
return address === applicationContext.account.address;
}

$scope.$on(events.ASSET_SELECTED, function (event, assetId) {
$scope.$on(events.ASSET_DETAILS, function (event, assetId) {
var asset = applicationContext.cache.assets[assetId];
if (angular.isUndefined(asset))
throw new Error('Failed to find asset details by id ' + assetId);
Expand All @@ -30,10 +30,12 @@
details.timestamp = asset.timestamp;
details.totalTokens = asset.totalTokens.formatAmount();
details.reissuable = asset.reissuable ? 'Yes' : 'No';

dialogService.open('#asset-details-dialog');
});
}

WavesAssetDetailsController.$inject = ['$scope', 'portfolio.events', 'applicationContext'];
WavesAssetDetailsController.$inject = ['$scope', 'portfolio.events', 'applicationContext', 'dialogService'];

angular
.module('app.portfolio')
Expand Down
9 changes: 7 additions & 2 deletions src/js/portfolio/asset.filter.js
Expand Up @@ -5,15 +5,20 @@
function transformAddress (rawAddress) {
var result = angular.isDefined(rawAddress) ? rawAddress : 'none';

if (result === applicationContext.account.address)
if (isMyAddress(result))
result = 'You';

return result;
}

function isMyAddress(address) {
return address === applicationContext.account.address;
}

function formatAsset (transaction) {
transaction.formatted = {
sender: transformAddress(transaction.sender)
sender: transformAddress(transaction.sender),
canReissue: transaction.reissuable && isMyAddress(transaction.sender)
};

transaction.formatted.isSenderCopiable = addressService.validateAddress(transaction.formatted.sender);
Expand Down
11 changes: 7 additions & 4 deletions src/js/portfolio/asset.list.controller.js
Expand Up @@ -10,6 +10,7 @@
assetList.assets = [];
assetList.assetTransfer = assetTransfer;
assetList.assetDetails = assetDetails;
assetList.assetReissue = assetReissue;
loadDataFromBackend();

$scope.$on('$destroy', function () {
Expand All @@ -28,13 +29,15 @@
}

function assetTransfer(assetId) {
$scope.$broadcast(events.ASSET_SELECTED, assetId);
dialogService.open('#transfer-asset-dialog');
$scope.$broadcast(events.ASSET_TRANSFER, assetId);
}

function assetDetails(assetId) {
$scope.$broadcast(events.ASSET_SELECTED, assetId);
dialogService.open('#asset-details-dialog');
$scope.$broadcast(events.ASSET_DETAILS, assetId);
}

function assetReissue(assetId) {
$scope.$broadcast(events.ASSET_REISSUE, assetId);
}

function tryToLoadAssetDataFromCache(asset) {
Expand Down
145 changes: 145 additions & 0 deletions src/js/portfolio/asset.reissue.controller.js
@@ -0,0 +1,145 @@
(function () {
'use strict';

var FIXED_REISSUE_FEE = new Money(1, Currency.WAV);

function WavesAssetReissueController($scope, $timeout, events, applicationContext, assetService, dialogService,
notificationService, formattingService, apiService) {
var transaction;
var reissue = this;
reissue.confirm = {
amount: {},
fee: {},
reissuePending: false
};
reissue.fee = FIXED_REISSUE_FEE;
reissue.validationOptions = {
rules: {
assetAmount: {
required: true,
decimal: 0,
min: 1
}
},
messages: {
assetAmount: {
required: 'Amount to reissue is required'
}
}
};
reissue.submitReissue = submitReissue;
reissue.broadcastTransaction = broadcastTransaction;

resetReissueForm();

$scope.$on(events.ASSET_REISSUE, function (event, assetId) {
var asset = applicationContext.cache.assets[assetId];
if (angular.isUndefined(asset))
throw new Error('Failed to find asset data by id ' + assetId);

reissue.assetId = assetId;
reissue.assetName = asset.currency.displayName;
reissue.totalTokens = asset.totalTokens.formatAmount();
reissue.asset = asset;

// update validation options and check how it affects form validation
reissue.validationOptions.rules.assetAmount.decimal = asset.currency.precision;
var minimumPayment = Money.fromCoins(1, asset.currency);
reissue.validationOptions.rules.assetAmount.min = minimumPayment.toTokens();
reissue.validationOptions.messages.assetAmount.decimal = 'The amount to reissue must be a number ' +
'with no more than ' + minimumPayment.currency.precision +
' digits after the decimal point (.)';
reissue.validationOptions.messages.assetAmount.min = 'Amount to reissue is too small. ' +
'It should be greater or equal to ' + minimumPayment.formatAmount(false);

dialogService.open('#asset-reissue-dialog');
});

function submitReissue () {
var form = getReissueForm();
if (!form.validate(reissue.validationOptions))
// prevent dialog from closing
return false;

var assetReissue = {
totalTokens: Money.fromTokens(reissue.amount, reissue.asset.currency),
reissuable: reissue.reissuable,
fee: reissue.fee
};

var sender = {
publicKey: applicationContext.account.keyPair.public,
privateKey: applicationContext.account.keyPair.private
};
// creating the transaction and waiting for confirmation
transaction = assetService.createAssetReissueTransaction(assetReissue, sender);

// setting data for the confirmation dialog
reissue.confirm.amount.value = assetReissue.totalTokens.formatAmount(true);
reissue.confirm.amount.currency = assetReissue.totalTokens.currency.displayName;
reissue.confirm.fee.value = assetReissue.fee.formatAmount(true);
reissue.confirm.fee.currency = assetReissue.fee.currency.displayName;

// open confirmation dialog
// doing it async because this method is called while another dialog is open
$timeout(function () {
dialogService.open('#asset-reissue-confirm-dialog');
}, 1);

resetReissueForm();

// it's ok to close reissue dialog
return true;
}

function broadcastTransaction () {
// checking if transaction was saved
if (angular.isUndefined(transaction))
return;

// prevent method execution when there is a pending reissue request
if (reissue.confirm.reissuePending)
return;

//disable confirm button
reissue.confirm.reissuePending = true;

apiService.assets.reissue(transaction).then(function () {
var amount = Money.fromCoins(transaction.quantity, reissue.asset);
var displayMessage = 'Reissued ' + amount.formatAmount(true) + ' tokens of asset ' +
reissue.asset.currency.displayName + '<br/>Date: ' +
formattingService.formatTimestamp(transaction.timestamp);
notificationService.notice(displayMessage);
//enable confirm button
reissue.confirm.reissuePending = false;
transaction = undefined;
}, function (response) {
if (angular.isDefined(response.data))
notificationService.error('Error:' + response.data.error + ' - ' + response.data.message);
else
notificationService.error('Request failed. Status: ' + response.status + ' - ' +
response.statusText);
//enable confirm button
reissue.confirm.reissuePending = false;
transaction = undefined;
});
}

function getReissueForm() {
// here we have a direct markup dependency
// but other ways of getting the form from a child scope are even more ugly
return angular.element('#asset-reissue-form').scope().assetReissueForm;
}

function resetReissueForm() {
reissue.amount = '0';
}
}

WavesAssetReissueController.$inject = ['$scope', '$timeout', 'portfolio.events', 'applicationContext',
'assetService', 'dialogService', 'notificationService', 'formattingService', 'apiService'];

angular
.module('app.portfolio')
.controller('assetReissueController', WavesAssetReissueController);
})();
7 changes: 4 additions & 3 deletions src/js/portfolio/asset.transfer.controller.js
Expand Up @@ -23,7 +23,6 @@
};
transfer.autocomplete = autocomplete;
transfer.validationOptions = {
debug: true,
rules: {
assetRecipient: {
required: true,
Expand Down Expand Up @@ -61,7 +60,7 @@

resetPaymentForm();

$scope.$on(events.ASSET_SELECTED, function (event, assetId) {
$scope.$on(events.ASSET_TRANSFER, function (event, assetId) {
var asset = applicationContext.cache.assets[assetId];
transfer.availableBalance = asset.balance.formatAmount();
transfer.asset = asset;
Expand All @@ -75,6 +74,8 @@
' digits after the decimal point (.)';
transfer.validationOptions.messages.assetAmount.min = 'Payment amount is too small. ' +
'It should be greater or equal to ' + minimumPayment.formatAmount(false);

dialogService.open('#asset-transfer-dialog');
});

function getTransferForm() {
Expand Down Expand Up @@ -139,7 +140,7 @@
var amount = Money.fromCoins(transaction.amount, transfer.asset);
var address = transaction.recipient;
var displayMessage = 'Sent ' + amount.formatAmount(true) + ' of ' +
transaction.asset.currency.displayName +
transfer.asset.currency.displayName +
'<br/>Recipient ' + address.substr(0,15) + '...<br/>Date: ' +
formattingService.formatTimestamp(transaction.timestamp);
notificationService.notice(displayMessage);
Expand Down
4 changes: 3 additions & 1 deletion src/js/portfolio/portfolio.module.js
Expand Up @@ -3,6 +3,8 @@

angular.module('app.portfolio', ['app.shared'])
.constant('portfolio.events', {
ASSET_SELECTED: 'asset-selected'
ASSET_TRANSFER: 'asset-transfer',
ASSET_REISSUE: 'asset-reissue',
ASSET_DETAILS: 'asset-details'
});
})();

0 comments on commit 9c98c0f

Please sign in to comment.