@ -0,0 +1,86 @@ |
|||
import { |
|||
triggerToaster |
|||
} from '../actionCreators'; |
|||
import { |
|||
logGuiHttp, |
|||
guiLogState |
|||
} from './log'; |
|||
import Config from '../../config'; |
|||
|
|||
export function getListUnspent(coin) { |
|||
return new Promise((resolve, reject) => { |
|||
const payload = { |
|||
mode: null, |
|||
chain: coin, |
|||
cmd: 'listunspent', |
|||
}; |
|||
|
|||
const _fetchConfig = { |
|||
method: 'POST', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
body: JSON.stringify({ 'payload': payload }), |
|||
}; |
|||
|
|||
fetch( |
|||
`http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, |
|||
_fetchConfig |
|||
) |
|||
.catch(function(error) { |
|||
console.log(error); |
|||
dispatch( |
|||
triggerToaster( |
|||
'getListUnspent', |
|||
'Error', |
|||
'error' |
|||
) |
|||
); |
|||
}) |
|||
.then(response => response.json()) |
|||
.then(json => { |
|||
resolve(json.result ? json.result : json); |
|||
}) |
|||
}); |
|||
} |
|||
|
|||
export function getRawTransaction(coin, txid) { |
|||
return new Promise((resolve, reject) => { |
|||
const payload = { |
|||
mode: null, |
|||
chain: coin, |
|||
cmd: 'getrawtransaction', |
|||
params: [ |
|||
txid, |
|||
1 |
|||
], |
|||
}; |
|||
|
|||
const _fetchConfig = { |
|||
method: 'POST', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
body: JSON.stringify({ 'payload': payload }), |
|||
}; |
|||
|
|||
fetch( |
|||
`http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, |
|||
_fetchConfig |
|||
) |
|||
.catch(function(error) { |
|||
console.log(error); |
|||
dispatch( |
|||
triggerToaster( |
|||
'getTransaction', |
|||
'Error', |
|||
'error' |
|||
) |
|||
); |
|||
}) |
|||
.then(response => response.json()) |
|||
.then(json => { |
|||
resolve(json.result ? json.result : json); |
|||
}) |
|||
}); |
|||
} |
@ -0,0 +1,164 @@ |
|||
import { |
|||
triggerToaster, |
|||
getNewKMDAddresses |
|||
} from '../actionCreators'; |
|||
import { |
|||
logGuiHttp, |
|||
guiLogState |
|||
} from './log'; |
|||
import Config from '../../config'; |
|||
|
|||
function getNewAddress(coin) { // TODO: remove(?)
|
|||
return new Promise((resolve, reject) => { |
|||
const payload = { |
|||
mode: null, |
|||
chain: coin, |
|||
cmd: 'getnewaddress' |
|||
}; |
|||
|
|||
const _fetchConfig = { |
|||
method: 'POST', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
body: JSON.stringify({ 'payload': payload }), |
|||
}; |
|||
|
|||
fetch( |
|||
`http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, |
|||
_fetchConfig |
|||
) |
|||
.catch(function(error) { |
|||
console.log(error); |
|||
dispatch( |
|||
triggerToaster( |
|||
'genJumblrAddress + getKMDAddressesNative', |
|||
'Error', |
|||
'error' |
|||
) |
|||
); |
|||
}) |
|||
.then(response => response.json()) |
|||
.then(json => { |
|||
resolve(json.result ? json.result : json); |
|||
}) |
|||
}); |
|||
} |
|||
|
|||
export function setJumblrAddress(coin, type, address) { |
|||
return new Promise((resolve, reject) => { |
|||
const payload = { |
|||
mode: null, |
|||
chain: coin, |
|||
cmd: type === 'deposit' ? 'jumblr_deposit' : 'jumblr_secret', |
|||
params: [address], |
|||
}; |
|||
|
|||
const _fetchConfig = { |
|||
method: 'POST', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
body: JSON.stringify({ 'payload': payload }), |
|||
}; |
|||
|
|||
fetch( |
|||
`http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, |
|||
_fetchConfig |
|||
) |
|||
.catch(function(error) { |
|||
console.log(error); |
|||
dispatch( |
|||
triggerToaster( |
|||
'setJumblrAddress', |
|||
'Error', |
|||
'error' |
|||
) |
|||
); |
|||
}) |
|||
.then(response => response.json()) |
|||
.then(json => { |
|||
resolve(json); |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
function dumpPrivkey(coin, key) { |
|||
return new Promise((resolve, reject) => { |
|||
const payload = { |
|||
mode: null, |
|||
chain: coin, |
|||
cmd: 'dumpprivkey', |
|||
params: [key], |
|||
}; |
|||
|
|||
const _fetchConfig = { |
|||
method: 'POST', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
body: JSON.stringify({ 'payload': payload }), |
|||
}; |
|||
|
|||
fetch( |
|||
`http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, |
|||
_fetchConfig |
|||
) |
|||
.catch(function(error) { |
|||
console.log(error); |
|||
dispatch( |
|||
triggerToaster( |
|||
'dumpPrivkey ', |
|||
'Error', |
|||
'error' |
|||
) |
|||
); |
|||
}) |
|||
.then(response => response.json()) |
|||
.then(json => { |
|||
resolve(json.result ? json.result : json); |
|||
}) |
|||
}); |
|||
} |
|||
|
|||
export function importPrivkey(coin, key) { |
|||
return new Promise((resolve, reject) => { |
|||
const payload = { |
|||
mode: null, |
|||
chain: coin, |
|||
cmd: 'importprivkey', |
|||
params: [ |
|||
key, |
|||
'', |
|||
false |
|||
], |
|||
}; |
|||
|
|||
const _fetchConfig = { |
|||
method: 'POST', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
body: JSON.stringify({ 'payload': payload }), |
|||
}; |
|||
|
|||
fetch( |
|||
`http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, |
|||
_fetchConfig |
|||
) |
|||
.catch(function(error) { |
|||
console.log(error); |
|||
dispatch( |
|||
triggerToaster( |
|||
'importPrivkey ', |
|||
'Error', |
|||
'error' |
|||
) |
|||
); |
|||
}) |
|||
.then(response => response.json()) |
|||
.then(json => { |
|||
resolve(json.result ? json.result : json); |
|||
}) |
|||
}); |
|||
} |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,136 @@ |
|||
import React from 'react'; |
|||
import ReactDOM from 'react-dom'; |
|||
import Store from '../../../store'; |
|||
import { |
|||
toggleClaimInterestModal, |
|||
getListUnspent, |
|||
getRawTransaction, |
|||
copyString, |
|||
sendToAddressPromise, |
|||
triggerToaster |
|||
} from '../../../actions/actionCreators'; |
|||
import { translate } from '../../../translate/translate'; |
|||
import { |
|||
ClaimInterestModalRender, |
|||
_ClaimInterestTableRender |
|||
} from './claimInterestModal.render'; |
|||
|
|||
class ClaimInterestModal extends React.Component { |
|||
constructor(props) { |
|||
super(props); |
|||
this.state = { |
|||
open: false, |
|||
isLoading: true, |
|||
transactionsList: [], |
|||
showZeroInterest: true, |
|||
}; |
|||
this.claimInterestTableRender = this.claimInterestTableRender.bind(this); |
|||
this.toggleZeroInterest = this.toggleZeroInterest.bind(this); |
|||
this.loadListUnspent = this.loadListUnspent.bind(this); |
|||
this.checkTransactionsListLength = this.checkTransactionsListLength.bind(this); |
|||
} |
|||
|
|||
componentWillMount() { |
|||
this.loadListUnspent(); |
|||
} |
|||
|
|||
loadListUnspent() { |
|||
let _transactionsList = []; |
|||
|
|||
getListUnspent(this.props.ActiveCoin.coin) |
|||
.then((json) => { |
|||
if (json && |
|||
json.length) { |
|||
for (let i = 0; i < json.length; i++) { |
|||
getRawTransaction(this.props.ActiveCoin.coin, json[i].txid) |
|||
.then((_json) => { |
|||
_transactionsList.push({ |
|||
address: json[i].address, |
|||
locktime: _json.locktime, |
|||
amount: json[i].amount, |
|||
interest: json[i].interest, |
|||
txid: json[i].txid, |
|||
}); |
|||
|
|||
if (i === json.length - 1) { |
|||
this.setState({ |
|||
transactionsList: _transactionsList, |
|||
isLoading: false, |
|||
}); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
claimInterest(address, amount) { |
|||
sendToAddressPromise(this.props.ActiveCoin.coin, this.state.transactionsList[0].address, this.props.ActiveCoin.balance.transparent) |
|||
.then((json) => { |
|||
if (json.error && |
|||
json.error.code) { |
|||
Store.dispatch( |
|||
triggerToaster( |
|||
json.error.message, |
|||
'Error', |
|||
'error' |
|||
) |
|||
); |
|||
} else if (json.result && json.result.length && json.result.length === 64) { |
|||
Store.dispatch( |
|||
triggerToaster( |
|||
`Your full balance is sent to address ${this.state.transactionsList[0].address}. Check back your new balance in a few minutes.`, |
|||
translate('TOASTR.WALLET_NOTIFICATION'), |
|||
'success', |
|||
false |
|||
) |
|||
); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
checkTransactionsListLength() { |
|||
if (this.state.transactionsList && this.state.transactionsList.length) { |
|||
return true; |
|||
} else if (!this.state.transactionsList || !this.state.transactionsList.length) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
toggleZeroInterest() { |
|||
this.setState({ |
|||
showZeroInterest: !this.state.showZeroInterest, |
|||
}); |
|||
} |
|||
|
|||
copyTxId(txid) { |
|||
Store.dispatch(copyString(txid, 'Transaction ID copied')); |
|||
} |
|||
|
|||
claimInterestTableRender() { |
|||
return _ClaimInterestTableRender.call(this); |
|||
} |
|||
|
|||
componentWillReceiveProps(props) { |
|||
if (props.Dashboard.displayClaimInterestModal !== this.state.open) { |
|||
this.setState({ |
|||
open: props.Dashboard.displayClaimInterestModal, |
|||
}); |
|||
} |
|||
|
|||
if (!this.state.open && |
|||
props.Dashboard.displayClaimInterestModal) { |
|||
this.loadListUnspent(); |
|||
} |
|||
} |
|||
|
|||
closeModal() { |
|||
Store.dispatch(toggleClaimInterestModal(false)); |
|||
} |
|||
|
|||
render() { |
|||
return ClaimInterestModalRender.call(this); |
|||
} |
|||
} |
|||
|
|||
export default ClaimInterestModal; |
@ -0,0 +1,132 @@ |
|||
import React from 'react'; |
|||
import { translate } from '../../../translate/translate'; |
|||
|
|||
const MIN_INTEREST_THRESHOLD = 0.001; |
|||
|
|||
export const _ClaimInterestTableRender = function() { |
|||
const _transactionsList = this.state.transactionsList; |
|||
let _items = []; |
|||
|
|||
for (let i = 0; i < _transactionsList.length; i++) { |
|||
if ((_transactionsList[i].interest === 0 && this.state.showZeroInterest) || (_transactionsList[i].amount > 0 && _transactionsList[i].interest > 0)) { |
|||
_items.push( |
|||
<tr key={ `${_transactionsList[i].txid}${_transactionsList[i].address}` }> |
|||
<td> |
|||
<button |
|||
className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn" |
|||
title={ translate('INDEX.COPY_TO_CLIPBOARD') } |
|||
onClick={ () => this.copyTxId(_transactionsList[i].txid) }> |
|||
<i className="icon wb-copy"></i> { translate('INDEX.COPY') } |
|||
</button> |
|||
</td> |
|||
<td>{ _transactionsList[i].address }</td> |
|||
<td className={ _transactionsList[i].amount > 10 ? 'green bold' : '' }>{ _transactionsList[i].amount }</td> |
|||
<td>{ _transactionsList[i].interest }</td> |
|||
<td className="locktime center"> |
|||
{ _transactionsList[i].locktime && |
|||
<i className="fa-check-circle green"></i> |
|||
} |
|||
{ !_transactionsList[i].locktime && |
|||
<i className="fa-exclamation-circle red"></i> |
|||
} |
|||
</td> |
|||
</tr> |
|||
); |
|||
} |
|||
} |
|||
|
|||
return ( |
|||
<span> |
|||
<div className="padding-bottom-20"> |
|||
<strong>Requirements to accrue interest:</strong> locktime field is set and amount is greater than <strong>10 KMD</strong> |
|||
</div> |
|||
<div className="text-left padding-top-10 padding-bottom-10"> |
|||
<label className="switch"> |
|||
<input |
|||
type="checkbox" |
|||
checked={ this.state.showZeroInterest } /> |
|||
<div |
|||
className="slider" |
|||
onClick={ this.toggleZeroInterest }></div> |
|||
</label> |
|||
<div |
|||
className="toggle-label margin-right-15 pointer" |
|||
onClick={ this.toggleZeroInterest }> |
|||
Show zero interest |
|||
</div> |
|||
</div> |
|||
<button |
|||
type="button" |
|||
className="btn btn-success waves-effect waves-light claim-btn" |
|||
onClick={ () => this.claimInterest() }> |
|||
<i className="icon fa-dollar"></i> Claim interest |
|||
</button> |
|||
<div className="table-scroll"> |
|||
<table className="table table-hover dataTable table-striped"> |
|||
<thead> |
|||
<tr> |
|||
<th></th> |
|||
<th>Address</th> |
|||
<th>Amount</th> |
|||
<th>Interest</th> |
|||
<th>Locktime</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{ _items } |
|||
</tbody> |
|||
<tfoot> |
|||
<tr> |
|||
<th></th> |
|||
<th>Address</th> |
|||
<th>Amount</th> |
|||
<th>Interest</th> |
|||
<th>Locktime</th> |
|||
</tr> |
|||
</tfoot> |
|||
</table> |
|||
</div> |
|||
</span> |
|||
); |
|||
}; |
|||
|
|||
export const ClaimInterestModalRender = function() { |
|||
return ( |
|||
<span> |
|||
<div className={ 'modal modal-claim-interest modal-3d-sign ' + (this.state.open ? 'show in' : 'fade hide') }> |
|||
<div className="modal-dialog modal-center modal-sm"> |
|||
<div className="modal-content"> |
|||
<div className="modal-header bg-orange-a400 wallet-send-header"> |
|||
<button |
|||
type="button" |
|||
className="close white" |
|||
onClick={ this.closeModal }> |
|||
<span>×</span> |
|||
</button> |
|||
<h4 className="modal-title white text-left">Claim interest</h4> |
|||
</div> |
|||
<div className="modal-body"> |
|||
<i |
|||
className="icon fa-refresh pointer refresh-icon" |
|||
onClick={ this.loadListUnspent }></i> |
|||
<div className="animsition vertical-align fade-in"> |
|||
<div className="page-content vertical-align-middle full-width"> |
|||
{ this.state.isLoading && |
|||
<span>Loading interest data...</span> |
|||
} |
|||
{ !this.state.isLoading && this.checkTransactionsListLength() && |
|||
<div>{ this.claimInterestTableRender() }</div> |
|||
} |
|||
{ !this.state.isLoading && !this.checkTransactionsListLength() && |
|||
<div>No data</div> |
|||
} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div className={ 'modal-backdrop ' + (this.state.open ? 'show in' : 'fade hide') }></div> |
|||
</span> |
|||
); |
|||
}; |