Browse Source

Merge branch 'feat_dojo_wallet_history_endpoint' into 'develop'

add export of xpub history in csv format

See merge request dojo/samourai-dojo!203
umbrel
kenshin-samourai 4 years ago
parent
commit
7cf9bccbc9
  1. 13
      accounts/transactions-rest-api.js
  2. 1
      doc/GET_txs.md
  3. 11
      static/admin/css/style.css
  4. 24
      static/admin/dmt/xpubs-tools/xpubs-tools.html
  5. 44
      static/admin/dmt/xpubs-tools/xpubs-tools.js
  6. 8
      static/admin/lib/api-wrapper.js

13
accounts/transactions-rest-api.js

@ -83,8 +83,15 @@ class TransactionsRestApi {
const active = apiHelper.parseEntities(req.query.active)
const page = req.query.page != null ? parseInt(req.query.page) : 0
const count = req.query.count != null ? parseInt(req.query.count) : keys.multiaddr.transactions
const excludeNullXfer = req.query.excludeNullXfer != null
const result = await walletService.getWalletTransactions(active, page, count)
if (excludeNullXfer) {
result.txs = result.txs.filter(tx => {
return tx['result'] != 0
})
}
const ret = JSON.stringify(result, null, 2)
HttpServer.sendRawData(res, ret)
@ -141,7 +148,11 @@ class TransactionsRestApi {
!req.query.count
|| validator.isInt(req.query.count)
if (!(isValidPage && isValidCount)) {
const isValidExcludeNull =
!req.query.excludeNullXfer
|| validator.isAlphanumeric(req.query.excludeNullXfer)
if (!(isValidPage && isValidCount && isValidExcludeNull)) {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(
req.query,

1
doc/GET_txs.md

@ -12,6 +12,7 @@ GET /txs?active=...
* **active** - `string` - A pipe-separated list of extended public keys and/or loose addresses and/or pubkeys (`xpub1|address1|address2|pubkey1|...`)
* **page** - `integer` - Index of the requested page (first page is index 0)
* **count** - `integer` - Number of transactions returned per page
* **excludeNullXfer** - `boolean` - Boolean flag indicating if transactions that don't change the balance should be excluded from the result (default = false)
* **at** - `string` (optional) - Access Token (json web token). Required if authentication is activated. Alternatively, the access token can be passed through the `Authorization` HTTP header (with the `Bearer` scheme).
### Examples

11
static/admin/css/style.css

@ -551,6 +551,17 @@ button {
display: inline-block;
}
#xpubs-export-actions span {
display: inline;
}
#xpubs-export-actions select {
width: 240px;
margin-left: 5px;
margin-right: 5px;
display: inline-block;
}
#xpubs-tool-details #xpub-value {
overflow: hidden;
}

24
static/admin/dmt/xpubs-tools/xpubs-tools.html

@ -59,16 +59,17 @@
<div id="xpubs-tool-actions" class="row box-main">
<div class="center">
<button id="btn-xpub-details-rescan" class="btn btn-success" type="button">RESCAN THIS XPUB</button>
<button id="btn-xpub-details-retype" class="btn btn-success" type="button">RETYPE THIS XPUB</button>
<button id="btn-xpub-details-delete" class="btn btn-success" type="button">DELETE THIS XPUB</button>
<button id="btn-xpub-details-rescan" class="btn btn-success" type="button">RESCAN</button>
<button id="btn-xpub-details-retype" class="btn btn-success" type="button">RETYPE</button>
<button id="btn-xpub-details-delete" class="btn btn-success" type="button">DELETE</button>
<button id="btn-xpub-details-export" class="btn btn-success" type="button">CSV EXPORT</button>
<button id="btn-xpub-details-reset" class="btn btn-success" type="button">SEARCH ANOTHER XPUB</button>
</div>
</div>
<div id="xpubs-rescans-actions" class="row box-main">
<div class="center">
<span>Rescan this xpub starting at index</span>
<span>Rescan this XPUB starting at index</span>
<input id="rescan-start-idx" type="text" value="0" placeholder="index">
<span> with a lookahead of </span>
<input id="rescan-lookahead" type="text" value="100" placeholder="#addresses">
@ -80,12 +81,25 @@
<div id="xpubs-deletion-actions" class="row box-main">
<div class="center">
<span>Do you want to delete this xpub?</span>
<span>Do you want to delete this XPUB?</span>
<button id="btn-xpub-delete-go" class="btn btn-success" type="button">DELETE</button>
<button id="btn-xpub-delete-cancel" class="btn btn-success" type="button">CANCEL</button>
</div>
</div>
<div id="xpubs-export-actions" class="row box-main">
<div class="center">
<span>Do you want to export a list of </span>
<select id="export-type" type="select" value="full">
<option value="full" selected>all the transactions</option>
<option value="notNull">the transactions modifying the balance</option>
</select>
<span> of this XPUB?</span>
<button id="btn-xpub-export-go" class="btn btn-success" type="button">EXPORT</button>
<button id="btn-xpub-export-cancel" class="btn btn-success" type="button">CANCEL</button>
</div>
</div>
<div id="xpubs-tool-details-row1" class="row box-main">
<!-- GENERAL INFO -->
<div id="box-general" class="halfwidth-left box">

44
static/admin/dmt/xpubs-tools/xpubs-tools.js

@ -12,10 +12,13 @@ const screenXpubsToolsScript = {
$('#btn-xpub-details-reset').click(() => {this.showSearchForm()})
$('#btn-xpub-details-rescan').click(() => {this.showRescanForm()})
$('#btn-xpub-details-delete').click(() => {this.showDeletionForm()})
$('#btn-xpub-details-export').click(() => {this.showExportForm()})
$('#btn-xpub-rescan-go').click(() => {this.rescanXpub()})
$('#btn-xpub-rescan-cancel').click(() => {this.hideRescanForm()})
$('#btn-xpub-delete-go').click(() => {this.deleteXpub()})
$('#btn-xpub-delete-cancel').click(() => {this.hideDeletionForm()})
$('#btn-xpub-export-go').click(() => {this.exportXpubHistory()})
$('#btn-xpub-export-cancel').click(() => {this.hideExportForm()})
$('#btn-xpub-import-go').click(() => {this.importXpub()})
$('#btn-xpub-details-retype').click(() => {this.showImportForm(true)})
$('#btn-xpub-import-cancel').click(() => {this.hideImportForm(this.isReimport)})
@ -33,6 +36,7 @@ const screenXpubsToolsScript = {
this.hideRescanForm()
this.hideDeletionForm()
this.hideExportForm()
this.showSearchForm()
$("#xpub").focus()
},
@ -148,6 +152,35 @@ const screenXpubsToolsScript = {
})
},
exportXpubHistory: function() {
lib_msg.displayMessage('Exporting the transactional history of this xpub. Please wait...')
const args = {
'active': this.currentXpub,
'page': 0,
'count': 1000000000
}
if ($('#export-type').val() == 'notNull')
args['excludeNullXfer'] = 1
return lib_api.getTransactions(args)
.then(result => {
if (result['txs'] && result['txs'].length > 0) {
let content = 'data:text/csv;charset=utf-8,'
content += 'height,txid,date,flow\n'
for (let tx of result['txs'])
content += `${tx['block_height']},${tx['hash']},${new Date(tx['time']*1000).toString()},${tx['result']/100000000}\n`
const encodedURI = encodeURI(content)
window.open(encodedURI)
}
this.hideExportForm()
lib_msg.displayInfo('Transactional history successfully exported.')
}).catch(e => {
lib_errors.processError(e)
})
},
checkRescanStatus: function(callback) {
this.rescanStatusTimerId = setTimeout(() => {
lib_api.getXpubRescanStatus(this.currentXpub)
@ -312,6 +345,17 @@ const screenXpubsToolsScript = {
$('#xpubs-tool-actions').show()
},
showExportForm: function() {
$('#xpubs-tool-actions').hide()
$('#xpubs-export-actions').show()
lib_msg.cleanMessagesUi()
},
hideExportForm: function() {
$('#xpubs-export-actions').hide()
$('#xpubs-tool-actions').show()
},
}
screenScripts.set('#screen-xpubs-tools', screenXpubsToolsScript)

8
static/admin/lib/api-wrapper.js

@ -156,6 +156,14 @@ const lib_api = {
)
},
/**
* Transactions
*/
getTransactions: function(arguments) {
let uri = this.baseUri + '/txs'
return this.sendGetUriEncoded(uri, arguments)
},
/**
* Rescans a range of blocks
*/

Loading…
Cancel
Save