forked from lthn/blockchain
Merge remote-tracking branch 'origin/frontend'
This commit is contained in:
commit
2bf88e3f5b
49 changed files with 7434 additions and 289 deletions
|
|
@ -125,6 +125,7 @@ namespace epee
|
|||
template<class stl_container, class t_storage>
|
||||
static bool serialize_stl_container_pod_val_as_blob(const stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
static_assert(std::is_trivial<typename stl_container::value_type>::value, "Item supposed to be 'trivial'(trivially copyable)");
|
||||
if(!container.size()) return true;
|
||||
std::string mb;
|
||||
mb.resize(sizeof(typename stl_container::value_type)*container.size());
|
||||
|
|
@ -140,6 +141,7 @@ namespace epee
|
|||
template<class stl_container, class t_storage>
|
||||
static bool unserialize_stl_container_pod_val_as_blob(stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
static_assert(std::is_trivial<typename stl_container::value_type>::value, "Item supposed to be 'trivial'(trivially copyable)");
|
||||
container.clear();
|
||||
std::string buff;
|
||||
bool res = stg.get_value(pname, buff, hparent_section);
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ namespace tools
|
|||
if (txe.count == 0 || (txe.read_only && txe.count == 1))
|
||||
{
|
||||
mdb_txn_abort(txe.ptx);
|
||||
if (!txe.read_only && txe.count)
|
||||
if (!txe.read_only && !txe.count)
|
||||
{
|
||||
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED(ABORTED)", LOG_LEVEL_3);
|
||||
|
|
|
|||
|
|
@ -1733,6 +1733,9 @@ bool blockchain_storage::get_main_block_rpc_details(uint64_t i, block_rpc_extend
|
|||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
auto core_bei_ptr = m_db_blocks[i];
|
||||
crypto::hash id = get_block_hash(core_bei_ptr->bl);
|
||||
crypto::hash pow_seed = null_hash;
|
||||
get_seed_for_scratchpad(i, pow_seed);
|
||||
bei.pow_seed = epee::string_tools::pod_to_hex(pow_seed);
|
||||
bei.is_orphan = false;
|
||||
bei.total_fee = 0;
|
||||
bei.total_txs_size = 0;
|
||||
|
|
@ -4303,7 +4306,8 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
if (!check_hash(proof_hash, current_diffic))
|
||||
{
|
||||
LOG_ERROR("Block with id: " << id << ENDL
|
||||
<< " : " << proof_hash << ENDL
|
||||
<< "PoW hash: " << proof_hash << ENDL
|
||||
<< "PoW seed: " << m_current_scratchpad_seed << ENDL
|
||||
<< "unexpected difficulty: " << current_diffic);
|
||||
bvc.m_verification_failed = true;
|
||||
return false;
|
||||
|
|
@ -5323,6 +5327,7 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx
|
|||
bool blockchain_storage::get_seed_for_scratchpad(uint64_t height, crypto::hash& seed)const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
LOG_PRINT_MAGENTA("Get seed for scratchpad [main_chain] on height " << height, LOG_LEVEL_0);
|
||||
return get_seed_for_scratchpad_cb(height, seed, [&](uint64_t index) -> crypto::hash
|
||||
{
|
||||
return get_block_hash(m_db_blocks[index]->bl);
|
||||
|
|
|
|||
|
|
@ -669,7 +669,7 @@ namespace currency
|
|||
crypto::hash genesis_seed = null_hash;
|
||||
bool r = epee::string_tools::hex_to_pod(CURRENCY_SCRATCHPAD_GENESIS_SEED, genesis_seed);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Unable to parse CURRENCY_SCRATCHPAD_GENESIS_SEED " << CURRENCY_SCRATCHPAD_GENESIS_SEED);
|
||||
LOG_PRINT_MAGENTA("[SCRATCHPAD] GENESIS SEED SELECTED: " << genesis_seed, LOG_LEVEL_1);
|
||||
LOG_PRINT_MAGENTA("[SCRATCHPAD] GENESIS SEED SELECTED: " << genesis_seed, LOG_LEVEL_0);
|
||||
seed = genesis_seed;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -688,7 +688,7 @@ namespace currency
|
|||
}
|
||||
seed = crypto::cn_fast_hash(&seed_data[0], sizeof(seed_data[0]) * seed_data.size());
|
||||
|
||||
LOG_PRINT_MAGENTA("[SCRATCHPAD] SEED SELECTED: h = " << last_upd_h << ", selector: " << selector_id << ENDL << ss.str() << "SEED: " << seed, LOG_LEVEL_1);
|
||||
LOG_PRINT_MAGENTA("[SCRATCHPAD] SEED SELECTED: h = " << last_upd_h << ", selector: " << selector_id << ENDL << ss.str() << "SEED: " << seed, LOG_LEVEL_0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,12 +64,13 @@ namespace currency
|
|||
stop();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::set_block_template(const block& bl, const wide_difficulty_type& di, uint64_t height)
|
||||
bool miner::set_block_template(const block& bl, const wide_difficulty_type& di, uint64_t height, const crypto::hash& seed)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_template_lock);
|
||||
m_template = bl;
|
||||
m_diffic = di;
|
||||
m_height = height;
|
||||
m_seed = seed;
|
||||
++m_template_no;
|
||||
m_starter_nonce = crypto::rand<uint32_t>();
|
||||
m_scratchpad.generate(m_seed, height);
|
||||
|
|
@ -95,12 +96,13 @@ namespace currency
|
|||
{
|
||||
extra_nonce += std::string("|") + m_extra_messages[m_config.current_extra_message_index];
|
||||
}
|
||||
if(!m_phandler->get_block_template(bl, m_seed, m_mine_address, m_mine_address, di, height, extra_nonce))
|
||||
crypto::hash seed = null_hash;
|
||||
if(!m_phandler->get_block_template(bl, seed, m_mine_address, m_mine_address, di, height, extra_nonce))
|
||||
{
|
||||
LOG_ERROR("Failed to get_block_template()");
|
||||
return false;
|
||||
}
|
||||
set_block_template(bl, di, height);
|
||||
set_block_template(bl, di, height, seed);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -307,6 +309,8 @@ namespace currency
|
|||
wide_difficulty_type local_diff = 0;
|
||||
uint32_t local_template_ver = 0;
|
||||
blobdata local_blob_data;
|
||||
crypto::hash local_seed = null_hash;
|
||||
uint64_t local_height = 0;
|
||||
|
||||
//uint64_t local_template_height = 0;
|
||||
block b;
|
||||
|
|
@ -324,6 +328,8 @@ namespace currency
|
|||
CRITICAL_REGION_BEGIN(m_template_lock);
|
||||
b = m_template;
|
||||
local_diff = m_diffic;
|
||||
local_seed = m_seed;
|
||||
local_height = m_height;
|
||||
CRITICAL_REGION_END();
|
||||
//local_template_height = get_block_height(b);
|
||||
local_template_ver = m_template_no;
|
||||
|
|
@ -339,7 +345,7 @@ namespace currency
|
|||
}
|
||||
b.nonce = nonce;
|
||||
access_nonce_in_block_blob(local_blob_data) = b.nonce;
|
||||
crypto::hash h = m_scratchpad.get_pow_hash(local_blob_data, m_height, m_seed);
|
||||
crypto::hash h = m_scratchpad.get_pow_hash(local_blob_data, local_height, local_seed);
|
||||
|
||||
if(check_hash(h, local_diff))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ namespace currency
|
|||
}
|
||||
|
||||
private:
|
||||
bool set_block_template(const block& bl, const wide_difficulty_type& diffic, uint64_t height);
|
||||
bool set_block_template(const block& bl, const wide_difficulty_type& diffic, uint64_t height, const crypto::hash& seed);
|
||||
bool worker_thread();
|
||||
bool request_block_template();
|
||||
void merge_hr();
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace currency
|
|||
crypto::hash scratchpad_keeper::get_pow_hash(const blobdata& bd, uint64_t height, const crypto::hash& scr_seed)
|
||||
{
|
||||
crypto::hash res_hash = null_hash;
|
||||
if (scr_seed != m_seed)
|
||||
if (scr_seed != m_seed || get_scratchpad_size_for_height(height) != this->size())
|
||||
{
|
||||
bool r = generate(scr_seed, height);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Unable to generate scratchpad");
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ int main(int argc, char* argv[])
|
|||
ccore.set_currency_protocol(&cprotocol);
|
||||
daemon_cmmands_handler dch(p2psrv, rpc_server);
|
||||
tools::miniupnp_helper upnp_helper;
|
||||
ccore.get_blockchain_storage().get_attachment_services_manager().add_service(&offers_service);
|
||||
//ccore.get_blockchain_storage().get_attachment_services_manager().add_service(&offers_service);
|
||||
|
||||
if (command_line::get_arg(vm, command_line::arg_show_rpc_autodoc))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ public:
|
|||
m_cmd_binder.set_handler("print_market", boost::bind(&daemon_cmmands_handler::print_market, this, _1));
|
||||
m_cmd_binder.set_handler("print_bc_outs_stat", boost::bind(&daemon_cmmands_handler::print_bc_outs_stat, this, _1));
|
||||
m_cmd_binder.set_handler("print_block", boost::bind(&daemon_cmmands_handler::print_block, this, _1), "Print block, print_block <block_hash> | <block_height>");
|
||||
m_cmd_binder.set_handler("print_block_info", boost::bind(&daemon_cmmands_handler::print_block_info, this, _1), "Print block info, print_block <block_hash> | <block_height>");
|
||||
m_cmd_binder.set_handler("print_tx", boost::bind(&daemon_cmmands_handler::print_tx, this, _1), "Print transaction, print_tx <transaction_hash>");
|
||||
m_cmd_binder.set_handler("start_mining", boost::bind(&daemon_cmmands_handler::start_mining, this, _1), "Start mining for specified address, start_mining <addr> [threads=1]");
|
||||
m_cmd_binder.set_handler("stop_mining", boost::bind(&daemon_cmmands_handler::stop_mining, this, _1), "Stop mining");
|
||||
|
|
@ -390,6 +391,23 @@ private:
|
|||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool print_block_info_by_height(uint64_t height)
|
||||
{
|
||||
std::list<currency::block_rpc_extended_info> blocks;
|
||||
bool r = m_srv.get_payload_object().get_core().get_blockchain_storage().get_main_blocks_rpc_details(height, 1, false, blocks);
|
||||
if (r && blocks.size())
|
||||
{
|
||||
currency::block_rpc_extended_info& rbei = blocks.back();
|
||||
LOG_PRINT_GREEN("------------------ block_id: " << rbei.id << " ------------------" << ENDL << epee::serialization::store_t_to_json(rbei), LOG_LEVEL_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_GREEN("block wasn't found: " << height, LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool print_block_by_hash(const std::string& arg)
|
||||
{
|
||||
crypto::hash block_hash;
|
||||
|
|
@ -443,6 +461,28 @@ private:
|
|||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool print_block_info(const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.empty())
|
||||
{
|
||||
std::cout << "expected: print_block_info (<block_hash> | <block_height>)" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string& arg = args.front();
|
||||
try
|
||||
{
|
||||
uint64_t height = boost::lexical_cast<uint64_t>(arg);
|
||||
print_block_by_height(height);
|
||||
}
|
||||
catch (boost::bad_lexical_cast&)
|
||||
{
|
||||
print_block_by_hash(arg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool print_tx(const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.empty())
|
||||
|
|
|
|||
|
|
@ -568,7 +568,7 @@ QString MainWindow::start_backend(const QString& params)
|
|||
return MAKE_RESPONSE(ar);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool r = m_backend.start();
|
||||
if (!r)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
"OLD_PURCHASE": "Purchase"
|
||||
},
|
||||
"SIDEBAR": {
|
||||
"TITLE": "Accounts",
|
||||
"TITLE": "Wallets",
|
||||
"ADD_NEW": "+ Add new",
|
||||
"ACCOUNT": {
|
||||
"STAKING": "Staking",
|
||||
|
|
@ -54,16 +54,16 @@
|
|||
"BUTTON_SELECT": "Select wallet location",
|
||||
"BUTTON_CREATE": "Create wallet",
|
||||
"TITLE_SAVE": "Save the wallet file.",
|
||||
"ERROR_CANNOT_SAVE_TOP": "You cannot record a file on top of another file",
|
||||
"ERROR_CANNOT_SAVE_SYSTEM": "You cannot save a safe file to the system partition"
|
||||
"ERROR_CANNOT_SAVE_TOP": "Existing wallet files cannot be replaced or overwritten",
|
||||
"ERROR_CANNOT_SAVE_SYSTEM": "Wallet files cannot be saved to the OS partition"
|
||||
},
|
||||
"OPEN_WALLET": {
|
||||
"NAME": "Wallet name",
|
||||
"PASS": "Wallet password",
|
||||
"BUTTON": "Open wallet",
|
||||
"WITH_ADDRESS_ALREADY_OPEN": "A wallet with this account is already open",
|
||||
"SAFE_FILE_NOT_FOUND1": "Safe file not found",
|
||||
"SAFE_FILE_NOT_FOUND2": "<br/><br/> It might have been renamed or moved. <br/> To open it, use the \"Open safe\" button."
|
||||
"WITH_ADDRESS_ALREADY_OPEN": "A wallet with this address is already open",
|
||||
"SAFE_FILE_NOT_FOUND1": "Wallet file not found",
|
||||
"SAFE_FILE_NOT_FOUND2": "<br/><br/> It might have been renamed or moved. <br/> To open it, use the \"Open wallet\" button."
|
||||
},
|
||||
"RESTORE_WALLET": {
|
||||
"LABEL_NAME": "Wallet name",
|
||||
|
|
@ -72,18 +72,18 @@
|
|||
"CONFIRM": "Confirm wallet password",
|
||||
"BUTTON_SELECT": "Select wallet location",
|
||||
"BUTTON_CREATE": "Create wallet",
|
||||
"NOT_CORRECT_FILE_OR_PASSWORD": "Invalid safe file or password does not match",
|
||||
"NOT_CORRECT_FILE_OR_PASSWORD": "Invalid wallet file or password does not match",
|
||||
"CHOOSE_PATH": "Please choose a path"
|
||||
},
|
||||
"SEED_PHRASE": {
|
||||
"TITLE": "Make sure to keep your seed phrase in a safe place. If you forget your seed phrase you will not be able to recover your account.",
|
||||
"BUTTON_CREATE_ACCOUNT" : "Create account"
|
||||
"TITLE": "Make sure to keep your seed phrase in a safe place. If you forget your seed phrase you will not be able to recover your wallet.",
|
||||
"BUTTON_CREATE_ACCOUNT" : "Create wallet"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "Settings",
|
||||
"DARK_THEME": "Dark theme",
|
||||
"WHITE_THEME": "White theme",
|
||||
"GRAY_THEME": "Gray theme",
|
||||
"GRAY_THEME": "Grey theme",
|
||||
"MASTER_PASSWORD": {
|
||||
"TITLE": "Update master password",
|
||||
"OLD": "Old password",
|
||||
|
|
@ -96,6 +96,9 @@
|
|||
"REGISTER_ALIAS": "Register an alias",
|
||||
"DETAILS": "Details",
|
||||
"LOCK": "Lock",
|
||||
"AVAILABLE_BALANCE": "Available <b>{{available}} {{currency}}<b/>",
|
||||
"LOCKED_BALANCE": "Locked <b>{{locked}} {{currency}}<b/>",
|
||||
"LOCKED_BALANCE_LINK": "What does that mean?",
|
||||
"TABS": {
|
||||
"SEND": "Send",
|
||||
"RECEIVE": "Receive",
|
||||
|
|
@ -121,7 +124,7 @@
|
|||
"MIXIN": "Mixin",
|
||||
"FEE": "Fee",
|
||||
"BUTTON": "Send",
|
||||
"SUCCESS_SENT": "The payment will be received within 20 minutes"
|
||||
"SUCCESS_SENT": "Transaction sent"
|
||||
},
|
||||
"HISTORY": {
|
||||
"STATUS": "Status",
|
||||
|
|
@ -131,7 +134,16 @@
|
|||
"DATE": "Date",
|
||||
"AMOUNT": "Amount",
|
||||
"FEE": "Fee",
|
||||
"ADDRESS": "Address"
|
||||
"ADDRESS": "Address",
|
||||
"DETAILS": {
|
||||
"ID": "Transaction ID",
|
||||
"SIZE": "Transaction size",
|
||||
"SIZE_VALUE": "{{value}} bytes",
|
||||
"HEIGHT": "Height",
|
||||
"CONFIRMATION": "Confirmation",
|
||||
"INPUTS": "Inputs",
|
||||
"OUTPUTS": "Outputs"
|
||||
}
|
||||
},
|
||||
"CONTRACTS": {
|
||||
"EMPTY": "No active contracts.",
|
||||
|
|
@ -175,13 +187,13 @@
|
|||
"PROGRESS_COMPLETE": "Completed",
|
||||
"FEE": "Fee",
|
||||
"PAYMENT": "Payment ID",
|
||||
"ACCEPT_STATE_WAIT_BIG": "You have accepted the contract proposal. Please wait for the pledges to be made",
|
||||
"ACCEPT_STATE_WAIT_BIG": "You have accepted the contract proposal. Please wait for the deposits to be made",
|
||||
"IGNORED_ACCEPT": "You have ignored the contract proposal",
|
||||
"BURN_PROPOSAL": "The pledges have been nullified.",
|
||||
"BURN_PROPOSAL": "The deposits have been voided.",
|
||||
"SUCCESS_FINISH_PROPOSAL": "The contract is complete. The payment has been sent.",
|
||||
"SEND_CANCEL_PROPOSAL": "Proposal to cancel contract sent to seller",
|
||||
"IGNORED_CANCEL": "You have ignored the proposal to cancel the contract",
|
||||
"DEALS_CANCELED_WAIT": "The contract is being cancelled. Please wait for the pledge to be returned",
|
||||
"DEALS_CANCELED_WAIT": "The contract is being cancelled. Please wait for the deposit to be returned",
|
||||
"WAITING_TIME": "Time until response"
|
||||
},
|
||||
"MESSAGES": {
|
||||
|
|
@ -194,18 +206,18 @@
|
|||
"NOT_ENOUGH_MONEY": "Insufficient funds in account",
|
||||
"CORE_BUSY": "Internal error (core is busy)",
|
||||
"DAEMON_BUSY": "Internal error: deamon is busy",
|
||||
"NO_MONEY_REMOVE_OFFER": "There is no fee for deleting an offer, but in order to protect the network against flood transactions you need to have at least {{fee}} {{currency}} in your safe",
|
||||
"NO_MONEY_REMOVE_OFFER": "There is no fee for deleting an offer, but in order to protect the network against flood transactions you need to have at least {{fee}} {{currency}} in your wallet",
|
||||
"NOT_ENOUGH_OUTPUTS_TO_MIX": "For the sake of security, mixed transaction will take several days",
|
||||
"TRANSACTION_IS_TO_BIG": "This transaction is large and was therefore denied by the network. Try sending the required amount in parts.",
|
||||
"TRANSFER_ATTEMPT": "There is no connection to the Zano network",
|
||||
"TRANSACTION_IS_TO_BIG": "Transaction exceeds network limit, send required amount with multiple transactions",
|
||||
"TRANSFER_ATTEMPT": "There is no connection to Zano network",
|
||||
"ACCESS_DENIED": "Access denied",
|
||||
"TRANSACTION_ERROR": "Error. Payment not completed.",
|
||||
"TRANSACTION_ERROR": "Error. Transaction not completed.",
|
||||
"BAD_ARG": "Invalid argument",
|
||||
"WALLET_WRONG_ID": "Invalid wallet ID",
|
||||
"WRONG_PASSWORD": "Invalid password",
|
||||
"FILE_RESTORED": "The safe file was corrupted somehow. We have recovered the keys and safe from the blockchain.",
|
||||
"FILE_RESTORED": "The wallet file was corrupted. We have recovered the keys and the wallet from the blockchain",
|
||||
"FILE_NOT_FOUND": "File not found",
|
||||
"FILE_EXIST": "A file with that name already exists. Enter another name to save the file under",
|
||||
"FILE_NOT_SAVED": "You cannot save a safe file in this folder. Please choose another folder."
|
||||
"FILE_NOT_SAVED": "You cannot save a wallet file in this folder. Please choose another folder."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,52 +385,55 @@ input[type='checkbox'].style-checkbox {
|
|||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
.balance-tooltip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 1.3rem;
|
||||
padding: 1.3rem;
|
||||
|
||||
@include themify($themes) {
|
||||
background: themed(modalBackground);
|
||||
background: themed(tooltipBackgroundColor);
|
||||
box-shadow: themed(tooltipShadow);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
.content {
|
||||
&.ng-tooltip-top {
|
||||
margin-top: -1rem;
|
||||
}
|
||||
|
||||
.icon.error {
|
||||
&.ng-tooltip-bottom {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(redTextColor);
|
||||
}
|
||||
}
|
||||
&.ng-tooltip-left {
|
||||
margin-left: -1rem;
|
||||
}
|
||||
|
||||
.icon.success {
|
||||
&.ng-tooltip-right {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(greenTextColor);
|
||||
}
|
||||
}
|
||||
.available {
|
||||
margin-bottom: 1.7rem;
|
||||
|
||||
.icon.info {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
b {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.action-button {
|
||||
.locked {
|
||||
margin-bottom: 0.7rem;
|
||||
|
||||
b {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
cursor: pointer;
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
color: themed(alternativeTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(closeButtonColor);
|
||||
}
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -472,3 +475,93 @@ input[type='checkbox'].style-checkbox {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
app-modal-container {
|
||||
|
||||
.modal {
|
||||
|
||||
@include themify($themes) {
|
||||
background: themed(modalBackground);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
.icon.error {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(redTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.icon.success {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(greenTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.icon.info {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-button {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
color: themed(alternativeTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(closeButtonColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app-transaction-details {
|
||||
|
||||
.table {
|
||||
|
||||
@include themify($themes) {
|
||||
border-top: 0.2rem solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
|
||||
.row {
|
||||
|
||||
.cell {
|
||||
|
||||
&.label {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(optionalTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
&.value {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
&.key-value {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,34 @@ app-history {
|
|||
|
||||
tr {
|
||||
|
||||
&:nth-child(4n+1) {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(tableBackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(4n+2) {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(tableBackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(4n+3) {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(4n+4) {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
|
||||
.confirmation {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -3256,10 +3256,10 @@ Zone.__load_patch('ZoneAwarePromise', function (global, Zone, api) {
|
|||
reject = rej;
|
||||
});
|
||||
function onResolve(value) {
|
||||
promise && (promise = null || resolve(value));
|
||||
promise && (promise = false || resolve(value));
|
||||
}
|
||||
function onReject(error) {
|
||||
promise && (promise = null || reject(error));
|
||||
promise && (promise = false || reject(error));
|
||||
}
|
||||
for (var _i = 0, values_1 = values; _i < values_1.length; _i++) {
|
||||
var value = values_1[_i];
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -6,10 +6,10 @@
|
|||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"build --watch": "ng build --output-path \"C:\\Program Files\\Zano\\html/\" --watch",
|
||||
"build --html": "ng build --output-path \"../html/\"",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"copy": "copyfiles -u 1 dist/**/* \"C:\\Program Files\\Zano\\html/\""
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
|
|
@ -26,18 +26,19 @@
|
|||
"@ngx-translate/core": "^11.0.0",
|
||||
"@ngx-translate/http-loader": "^4.0.0",
|
||||
"angular-highcharts": "^7.0.2",
|
||||
"copyfiles": "^2.1.0",
|
||||
"bignumber.js": "^8.0.2",
|
||||
"core-js": "^2.5.4",
|
||||
"highcharts": "^6.2.0",
|
||||
"idlejs": "^2.0.1",
|
||||
"inputmask": "^4.0.4",
|
||||
"json-bignumber": "^1.0.1",
|
||||
"ngx-contextmenu": "^5.1.1",
|
||||
"qrcode": "^1.3.0",
|
||||
"rxjs": "~6.3.3",
|
||||
"zone.js": "~0.8.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.10.0",
|
||||
"@angular-devkit/build-angular": "^0.12.2",
|
||||
"@angular/cli": "~7.0.2",
|
||||
"@angular/compiler-cli": "~7.0.0",
|
||||
"@angular/language-service": "~7.0.0",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<i class="icon" [class.error]="type === 'error'" [class.success]="type === 'success'" [class.info]="type === 'info'"></i>
|
||||
<div class="message-container">
|
||||
<span class="title">{{title}}</span>
|
||||
<span class="message">{{message}}</span>
|
||||
<span class="message" [innerHTML]="message"></span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="action-button" (click)="onClose()" #btn>OK</button>
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@ export class TooltipDirective {
|
|||
|
||||
@HostBinding('style.cursor') cursor = 'pointer';
|
||||
|
||||
@Input('tooltip') tooltipTitle: string;
|
||||
@Input('tooltip') tooltipInner: any;
|
||||
@Input() placement: string;
|
||||
@Input() tooltipClass: string;
|
||||
@Input() delay: number;
|
||||
@Input() timeout = 0;
|
||||
@Input() delay = 0;
|
||||
tooltip: HTMLElement;
|
||||
|
||||
removeTooltipTimeout;
|
||||
|
|
@ -39,11 +40,13 @@ export class TooltipDirective {
|
|||
}
|
||||
|
||||
hide() {
|
||||
this.renderer.setStyle(this.tooltip, 'opacity', '0');
|
||||
this.removeTooltipTimeout = setTimeout(() => {
|
||||
this.renderer.removeChild(document.body, this.tooltip);
|
||||
this.tooltip = null;
|
||||
}, this.delay);
|
||||
this.removeTooltipTimeout = setTimeout( () => {
|
||||
this.renderer.setStyle(this.tooltip, 'opacity', '0');
|
||||
window.setTimeout(() => {
|
||||
this.renderer.removeChild(document.body, this.tooltip);
|
||||
this.tooltip = null;
|
||||
}, this.delay);
|
||||
}, this.timeout);
|
||||
}
|
||||
|
||||
cancelHide() {
|
||||
|
|
@ -52,8 +55,12 @@ export class TooltipDirective {
|
|||
}
|
||||
|
||||
create() {
|
||||
this.tooltip = this.renderer.createElement('span');
|
||||
this.renderer.appendChild(this.tooltip, this.renderer.createText(this.tooltipTitle));
|
||||
if (typeof this.tooltipInner === 'string') {
|
||||
this.tooltip = this.renderer.createElement('div');
|
||||
this.tooltip.innerHTML = this.tooltipInner;
|
||||
} else {
|
||||
this.tooltip = this.tooltipInner;
|
||||
}
|
||||
this.renderer.appendChild(document.body, this.tooltip);
|
||||
this.renderer.setStyle(document.body, 'position', 'relative');
|
||||
this.renderer.setStyle(this.tooltip, 'position', 'absolute');
|
||||
|
|
@ -66,16 +73,14 @@ export class TooltipDirective {
|
|||
this.placement = 'top';
|
||||
this.renderer.addClass(this.tooltip, 'ng-tooltip-top');
|
||||
}
|
||||
if (this.delay !== null) {
|
||||
this.renderer.setStyle(this.tooltip, 'opacity', '0');
|
||||
this.renderer.setStyle(this.tooltip, '-webkit-transition', `opacity ${this.delay}ms`);
|
||||
this.renderer.setStyle(this.tooltip, '-moz-transition', `opacity ${this.delay}ms`);
|
||||
this.renderer.setStyle(this.tooltip, '-o-transition', `opacity ${this.delay}ms`);
|
||||
this.renderer.setStyle(this.tooltip, 'transition', `opacity ${this.delay}ms`);
|
||||
window.setTimeout(() => {
|
||||
this.renderer.setStyle(this.tooltip, 'opacity', '1');
|
||||
}, 0);
|
||||
}
|
||||
this.renderer.setStyle(this.tooltip, 'opacity', '0');
|
||||
this.renderer.setStyle(this.tooltip, '-webkit-transition', `opacity ${this.delay}ms`);
|
||||
this.renderer.setStyle(this.tooltip, '-moz-transition', `opacity ${this.delay}ms`);
|
||||
this.renderer.setStyle(this.tooltip, '-o-transition', `opacity ${this.delay}ms`);
|
||||
this.renderer.setStyle(this.tooltip, 'transition', `opacity ${this.delay}ms`);
|
||||
window.setTimeout(() => {
|
||||
this.renderer.setStyle(this.tooltip, 'opacity', '1');
|
||||
}, 0);
|
||||
}
|
||||
|
||||
setPosition() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<div class="table">
|
||||
<div class="row">
|
||||
<span class="cell label" [style.flex-basis]="cellSizes['1']">{{ 'HISTORY.DETAILS.ID' | translate }}</span>
|
||||
<span class="cell key-value" [style.flex-basis]="cellSizes['2']">{{transaction.tx_hash}}</span>
|
||||
<span class="cell label" [style.flex-basis]="cellSizes['3']">{{ 'HISTORY.DETAILS.SIZE' | translate }}</span>
|
||||
<span class="cell value" [style.flex-basis]="cellSizes['4']">{{ 'HISTORY.DETAILS.SIZE_VALUE' | translate : {value: transaction.tx_blob_size} }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="cell label" [style.flex-basis]="cellSizes['1']">{{ 'HISTORY.DETAILS.HEIGHT' | translate }}</span>
|
||||
<span class="cell value" [style.flex-basis]="cellSizes['2']">{{transaction.height}}</span>
|
||||
<span class="cell label" [style.flex-basis]="cellSizes['3']">{{ 'HISTORY.DETAILS.CONFIRMATION' | translate }}</span>
|
||||
<span class="cell value" [style.flex-basis]="cellSizes['4']">{{variablesService.height_app - transaction.height}}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="cell label" [style.flex-basis]="cellSizes['1']">{{ 'HISTORY.DETAILS.INPUTS' | translate }}</span>
|
||||
<span class="cell value" [style.flex-basis]="cellSizes['2']">{{transaction.td['rcv']?.length || 0}}</span>
|
||||
<span class="cell label" [style.flex-basis]="cellSizes['3']">{{ 'HISTORY.DETAILS.OUTPUTS' | translate }}</span>
|
||||
<span class="cell value" [style.flex-basis]="cellSizes['4']">{{transaction.td['spn']?.length || 0}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
:host {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.table {
|
||||
border-top: 0.2rem solid #ebebeb;
|
||||
margin: 0 3rem;
|
||||
padding: 0.5rem 0;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
border-top: none;
|
||||
line-height: 3rem;
|
||||
margin: 0 -0.5rem;
|
||||
width: 100%;
|
||||
height: 3rem;
|
||||
|
||||
.cell {
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
padding: 0 0.5rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TransactionDetailsComponent } from './transaction-details.component';
|
||||
|
||||
describe('TransactionDetailsComponent', () => {
|
||||
let component: TransactionDetailsComponent;
|
||||
let fixture: ComponentFixture<TransactionDetailsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ TransactionDetailsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TransactionDetailsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import {Component, OnInit, Input} from '@angular/core';
|
||||
import {Transaction} from '../../models/transaction.model';
|
||||
import {VariablesService} from "../../services/variables.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-transaction-details',
|
||||
templateUrl: './transaction-details.component.html',
|
||||
styleUrls: ['./transaction-details.component.scss']
|
||||
})
|
||||
export class TransactionDetailsComponent implements OnInit {
|
||||
|
||||
@Input() transaction: Transaction;
|
||||
cellSizes = {
|
||||
1: '25%',
|
||||
2: '25%',
|
||||
3: '25%',
|
||||
4: '25%'
|
||||
};
|
||||
|
||||
constructor(private variablesService: VariablesService) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import {BigNumber} from "bignumber.js";
|
||||
|
||||
export class Transaction {
|
||||
amount: BigNumber;
|
||||
comment: string;
|
||||
contract: any[];
|
||||
fee: BigNumber;
|
||||
height: number;
|
||||
is_income: boolean;
|
||||
is_mining: boolean;
|
||||
is_mixing: boolean;
|
||||
is_service: boolean;
|
||||
payment_id: string;
|
||||
show_sender: boolean;
|
||||
td: object;
|
||||
timestamp: number;
|
||||
tx_blob_size: number;
|
||||
tx_hash: string;
|
||||
tx_type: number;
|
||||
unlock_time: number;
|
||||
|
||||
sortAmount?: BigNumber;
|
||||
sortFee?: BigNumber;
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
import {Contract} from './contract.model';
|
||||
import {Transaction} from './transaction.model';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
|
||||
export class Wallet {
|
||||
wallet_id: number;
|
||||
|
|
@ -6,8 +8,8 @@ export class Wallet {
|
|||
pass: string;
|
||||
path: string;
|
||||
address: string;
|
||||
balance: number;
|
||||
unlocked_balance: number;
|
||||
balance: BigNumber;
|
||||
unlocked_balance: BigNumber;
|
||||
mined_total: number;
|
||||
tracking_hey: string;
|
||||
|
||||
|
|
@ -16,15 +18,15 @@ export class Wallet {
|
|||
new_messages?: number;
|
||||
new_contracts?: number;
|
||||
|
||||
history: any[];
|
||||
excluded_history: any[];
|
||||
history: Array<Transaction> = [];
|
||||
excluded_history: Array<Transaction> = [];
|
||||
|
||||
contracts: Array<Contract> = [];
|
||||
|
||||
progress?: number;
|
||||
loaded?: boolean;
|
||||
|
||||
constructor(id, name, pass, path, address, balance = 0, unlocked_balance = 0, mined = 0, tracking = '') {
|
||||
constructor(id, name, pass, path, address, balance, unlocked_balance, mined = 0, tracking = '') {
|
||||
this.wallet_id = id;
|
||||
this.name = name;
|
||||
this.pass = pass;
|
||||
|
|
@ -48,7 +50,7 @@ export class Wallet {
|
|||
}
|
||||
|
||||
getMoneyEquivalent(equivalent) {
|
||||
return this.balance * equivalent;
|
||||
return this.balance.multipliedBy(equivalent).toFixed(0);
|
||||
}
|
||||
|
||||
havePass(): boolean {
|
||||
|
|
@ -59,19 +61,19 @@ export class Wallet {
|
|||
return this.wallet_id === id;
|
||||
}
|
||||
|
||||
prepareHistoryItem(item: any): any {
|
||||
prepareHistoryItem(item: Transaction): any {
|
||||
if (item.tx_type === 4) {
|
||||
item.sortFee = -(item.amount + item.fee);
|
||||
item.sortAmount = 0;
|
||||
item.sortFee = item.amount.plus(item.fee).negated();
|
||||
item.sortAmount = new BigNumber(0);
|
||||
} else if (item.tx_type === 3) {
|
||||
item.sortFee = 0;
|
||||
item.sortFee = new BigNumber(0);
|
||||
} else if ((item.hasOwnProperty('contract') && (item.contract[0].state === 3 || item.contract[0].state === 6 || item.contract[0].state === 601) && !item.contract[0].is_a)) {
|
||||
item.sortFee = -item.fee;
|
||||
item.sortAmount = item.amount;
|
||||
item.sortFee = item.fee.negated();
|
||||
item.sortAmount = item.amount.negated();
|
||||
} else {
|
||||
if (!item.is_income) {
|
||||
item.sortFee = -item.fee;
|
||||
item.sortAmount = -item.amount;
|
||||
item.sortFee = item.fee.negated();
|
||||
item.sortAmount = item.amount.negated();
|
||||
} else {
|
||||
item.sortAmount = item.amount;
|
||||
}
|
||||
|
|
@ -79,9 +81,9 @@ export class Wallet {
|
|||
return item;
|
||||
}
|
||||
|
||||
prepareHistory(items: any[]): void {
|
||||
prepareHistory(items: Transaction[]): void {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if ((items[i].tx_type === 7 && items[i].is_income) || (items[i].tx_type === 11 && items[i].is_income) || (items[i].amount === 0 && items[i].fee === 0)) {
|
||||
if ((items[i].tx_type === 7 && items[i].is_income) || (items[i].tx_type === 11 && items[i].is_income) || (items[i].amount.eq(0) && items[i].fee.eq(0))) {
|
||||
let exists = false;
|
||||
for (let j = 0; j < this.excluded_history.length; j++) {
|
||||
if (this.excluded_history[j].tx_hash === items[i].tx_hash) {
|
||||
|
|
@ -191,7 +193,8 @@ export class Wallet {
|
|||
}
|
||||
const searchResult = viewedContracts.some(elem => elem.state === contract.state && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);
|
||||
contract.is_new = !searchResult;
|
||||
contract['private_detailes'].a_pledge += contract['private_detailes'].to_pay;
|
||||
|
||||
contract['private_detailes'].a_pledge = contract['private_detailes'].a_pledge.plus(contract['private_detailes'].to_pay);
|
||||
|
||||
safe.contracts.push(contract);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
import {VariablesService} from '../services/variables.service';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
|
||||
@Pipe({
|
||||
name: 'intToMoney'
|
||||
|
|
@ -12,8 +13,14 @@ export class IntToMoneyPipe implements PipeTransform {
|
|||
if (value === 0 || value === undefined) {
|
||||
return '0';
|
||||
}
|
||||
let maxFraction = this.variablesService.digits;
|
||||
if (args) {
|
||||
maxFraction = parseInt(args, 10);
|
||||
}
|
||||
const power = Math.pow(10, this.variablesService.digits);
|
||||
let str = (value / power).toFixed(this.variablesService.digits);
|
||||
// let str = (value / power).toFixed(maxFraction);
|
||||
let str = (new BigNumber(value)).div(power).toFixed(maxFraction);
|
||||
|
||||
for (let i = str.length - 1; i >= 0; i--) {
|
||||
if (str[i] !== '0') {
|
||||
str = str.substr(0, i + 1);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
import {VariablesService} from '../services/variables.service';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
|
||||
@Pipe({
|
||||
name: 'moneyToInt'
|
||||
|
|
@ -36,7 +37,7 @@ export class MoneyToIntPipe implements PipeTransform {
|
|||
am_str = am_str + '0';
|
||||
}
|
||||
}
|
||||
result = parseInt(am_str, 10);
|
||||
result = (new BigNumber(am_str)).integerValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import {TranslateService} from '@ngx-translate/core';
|
|||
import {VariablesService} from './variables.service';
|
||||
import {ModalService} from './modal.service';
|
||||
import {MoneyToIntPipe} from '../pipes/money-to-int.pipe';
|
||||
import JSONBigNumber from 'json-bignumber';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
|
||||
@Injectable()
|
||||
export class BackendService {
|
||||
|
|
@ -132,6 +134,17 @@ export class BackendService {
|
|||
}
|
||||
}
|
||||
|
||||
private bigNumberParser(key, val) {
|
||||
if (val.constructor.name === 'BigNumber' && ['balance', 'unlocked_balance', 'amount', 'fee', 'b_fee', 'to_pay', 'a_pledge', 'b_pledge'].indexOf(key) === -1) {
|
||||
return val.toNumber();
|
||||
}
|
||||
if (key === 'rcv' || key === 'spn') {
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
val[i] = new BigNumber(val[i]);
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
private commandDebug(command, params, result) {
|
||||
this.Debug(2, '----------------- ' + command + ' -----------------');
|
||||
|
|
@ -141,7 +154,7 @@ export class BackendService {
|
|||
};
|
||||
this.Debug(2, debug);
|
||||
try {
|
||||
this.Debug(2, JSON.parse(result));
|
||||
this.Debug(2, JSONBigNumber.parse(result, this.bigNumberParser));
|
||||
} catch (e) {
|
||||
this.Debug(2, {response_data: result, error_code: 'OK'});
|
||||
}
|
||||
|
|
@ -158,7 +171,7 @@ export class BackendService {
|
|||
Result = {};
|
||||
} else {
|
||||
try {
|
||||
Result = JSON.parse(resultStr);
|
||||
Result = JSONBigNumber.parse(resultStr, this.bigNumberParser);
|
||||
} catch (e) {
|
||||
Result = {response_data: resultStr, error_code: 'OK'};
|
||||
}
|
||||
|
|
@ -202,7 +215,7 @@ export class BackendService {
|
|||
this.Debug(0, 'Run Command Error! Command "' + command + '" don\'t found in backendObject');
|
||||
} else {
|
||||
const that = this;
|
||||
params = (typeof params === 'string') ? params : JSON.stringify(params);
|
||||
params = (typeof params === 'string') ? params : JSONBigNumber.stringify(params);
|
||||
if (params === undefined || params === '{}') {
|
||||
Action(function (resultStr) {
|
||||
that.commandDebug(command, params, resultStr);
|
||||
|
|
@ -224,7 +237,7 @@ export class BackendService {
|
|||
this.backendObject[command].connect(callback);
|
||||
} else {
|
||||
this.backendObject[command].connect((str) => {
|
||||
callback(JSON.parse(str));
|
||||
callback(JSONBigNumber.parse(str, this.bigNumberParser));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -390,7 +403,7 @@ export class BackendService {
|
|||
a_addr: a_addr,
|
||||
b_addr: b_addr,
|
||||
to_pay: this.moneyToIntPipe.transform(to_pay),
|
||||
a_pledge: this.moneyToIntPipe.transform(a_pledge) - this.moneyToIntPipe.transform(to_pay),
|
||||
a_pledge: this.moneyToIntPipe.transform((new BigNumber(a_pledge)).minus(to_pay).toString()),
|
||||
b_pledge: this.moneyToIntPipe.transform(b_pledge)
|
||||
},
|
||||
payment_id: payment_id,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.backend.eventSubscribe('quit_requested', () => {
|
||||
if (!this.onQuitRequest) {
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/']);
|
||||
});
|
||||
this.backend.storeSecureAppData(() => {
|
||||
this.backend.storeAppData(() => {
|
||||
const recursionCloseWallets = () => {
|
||||
|
|
@ -253,7 +256,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
const searchResult = this.variablesService.settings.viewedContracts.some(elem => elem.state === contract.state && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);
|
||||
contract.is_new = !searchResult;
|
||||
|
||||
contract['private_detailes'].a_pledge += contract['private_detailes'].to_pay;
|
||||
contract['private_detailes'].a_pledge = contract['private_detailes'].a_pledge.plus(contract['private_detailes'].to_pay);
|
||||
|
||||
let findContract = false;
|
||||
for (let i = 0; i < safe.contracts.length; i++) {
|
||||
|
|
@ -363,7 +366,11 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.backend.getAppData((status, data) => {
|
||||
if (data && Object.keys(data).length > 0) {
|
||||
this.variablesService.settings = data;
|
||||
for (const key in data) {
|
||||
if (data.hasOwnProperty(key) && this.variablesService.settings.hasOwnProperty(key)) {
|
||||
this.variablesService.settings[key] = data[key];
|
||||
}
|
||||
}
|
||||
if (this.variablesService.settings.hasOwnProperty('theme') && ['dark', 'white', 'gray'].indexOf(this.variablesService.settings.theme) !== -1) {
|
||||
this.renderer.addClass(document.body, 'theme-' + this.variablesService.settings.theme);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
|
|||
import { ChartModule, HIGHCHARTS_MODULES, Highcharts} from 'angular-highcharts';
|
||||
import { InputValidateDirective } from './_helpers/directives/input-validate/input-validate.directive';
|
||||
import { ModalContainerComponent } from './_helpers/directives/modal-container/modal-container.component';
|
||||
import { TransactionDetailsComponent } from './_helpers/directives/transaction-details/transaction-details.component';
|
||||
// import * as more from 'highcharts/highcharts-more.src';
|
||||
// import * as exporting from 'highcharts/modules/exporting.src';
|
||||
// import * as highstock from 'highcharts/modules/stock.src';
|
||||
|
|
@ -86,7 +87,8 @@ Highcharts.setOptions({
|
|||
ContractTimeLeftPipe,
|
||||
TooltipDirective,
|
||||
InputValidateDirective,
|
||||
ModalContainerComponent
|
||||
ModalContainerComponent,
|
||||
TransactionDetailsComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
|
|
|||
|
|
@ -10,29 +10,36 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of variablesService.currentWallet.history">
|
||||
<td>
|
||||
<div class="status" [class.send]="!item.is_income" [class.received]="item.is_income">
|
||||
<ng-container *ngIf="variablesService.height_app - item.height <= 10 || item.height === 0 || (item.is_mining && item.height === 0)">
|
||||
<div class="confirmation" tooltip="{{ 'HISTORY.STATUS_TOOLTIP' | translate : {'current': getHeight(item)/10, 'total': 10} }}" placement="bottom" tooltipClass="history-tooltip" delay="500">
|
||||
<div class="fill" [style.height]="getHeight(item) + '%'"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<i class="icon"></i>
|
||||
<span>{{ (item.is_income ? 'HISTORY.RECEIVED' : 'HISTORY.SEND') | translate }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{item.timestamp * 1000 | date : 'dd-MM-yyyy HH:mm'}}</td>
|
||||
<td>
|
||||
<span *ngIf="item.sortAmount">{{item.sortAmount | intToMoney}} {{variablesService.defaultCurrency}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span *ngIf="item.sortFee">{{item.sortFee | intToMoney}} {{variablesService.defaultCurrency}}</span>
|
||||
</td>
|
||||
<td class="remote-address">
|
||||
<span>{{item | historyTypeMessages}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<ng-container *ngFor="let item of variablesService.currentWallet.history; let index = index">
|
||||
<tr (click)="openDetails(index)">
|
||||
<td>
|
||||
<div class="status" [class.send]="!item.is_income" [class.received]="item.is_income">
|
||||
<ng-container *ngIf="variablesService.height_app - item.height < 10 || item.height === 0 && item.timestamp > 0">
|
||||
<div class="confirmation" tooltip="{{ 'HISTORY.STATUS_TOOLTIP' | translate : {'current': getHeight(item)/10, 'total': 10} }}" placement="bottom" tooltipClass="history-tooltip" [delay]="500">
|
||||
<div class="fill" [style.height]="getHeight(item) + '%'"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<i class="icon"></i>
|
||||
<span>{{ (item.is_income ? 'HISTORY.RECEIVED' : 'HISTORY.SEND') | translate }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{item.timestamp * 1000 | date : 'dd-MM-yyyy HH:mm'}}</td>
|
||||
<td>
|
||||
<span *ngIf="item.sortAmount && item.sortAmount.toString() !== '0'">{{item.sortAmount | intToMoney}} {{variablesService.defaultCurrency}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span *ngIf="item.sortFee && item.sortFee.toString() !== '0'">{{item.sortFee | intToMoney}} {{variablesService.defaultCurrency}}</span>
|
||||
</td>
|
||||
<td class="remote-address">
|
||||
<span>{{item | historyTypeMessages}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="transaction-details" [class.open]="index === openedDetails">
|
||||
<td colspan="5">
|
||||
<app-transaction-details *ngIf="index === openedDetails" [transaction]="item"></app-transaction-details>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -57,6 +57,29 @@
|
|||
text-overflow: ellipsis;
|
||||
max-width: 25vw;
|
||||
}
|
||||
|
||||
&:not(.transaction-details) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.transaction-details {
|
||||
-webkit-transition: 0.5s height linear, 0s font-size;
|
||||
transition: 0.5s height linear, 0s font-size;
|
||||
transition-delay: 0s, 0.5s;
|
||||
height: 0;
|
||||
|
||||
&.open {
|
||||
height: 10.2rem;
|
||||
}
|
||||
|
||||
td {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
line-height: inherit;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ import {VariablesService} from '../_helpers/services/variables.service';
|
|||
})
|
||||
export class HistoryComponent implements OnInit, OnDestroy {
|
||||
|
||||
constructor(private variablesService: VariablesService) {
|
||||
}
|
||||
openedDetails = false;
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
constructor(private variablesService: VariablesService) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
getHeight(item) {
|
||||
if ((this.variablesService.height_app - item.height >= 10 && item.height !== 0) || (item.is_mining === true && item.height === 0)) {
|
||||
|
|
@ -26,7 +26,14 @@ export class HistoryComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
openDetails(index) {
|
||||
if (index === this.openedDetails) {
|
||||
this.openedDetails = false;
|
||||
} else {
|
||||
this.openedDetails = index;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@
|
|||
|
||||
<div class="purchase-states" *ngIf="!newPurchase">
|
||||
|
||||
<ng-container *ngIf="currentContract.state == 1 && !currentContract.is_a && (currentContract.private_detailes.b_pledge + ('0.01' | moneyToInt) + ('0.01' | moneyToInt)) > variablesService.currentWallet.unlocked_balance">
|
||||
<ng-container *ngIf="currentContract.state == 1 && !currentContract.is_a && currentContract.private_detailes.b_pledge.plus(('0.01' | moneyToInt)).plus(('0.01' | moneyToInt)).isGreaterThan(variablesService.currentWallet.unlocked_balance)">
|
||||
<span>{{ 'There are insufficient funds in the safe. Add funds to the safe to continue' | translate }}</span>
|
||||
</ng-container>
|
||||
|
||||
|
|
@ -177,7 +177,7 @@
|
|||
<ng-container *ngIf="currentContract.state == 201 || currentContract.state == 601">
|
||||
<span *ngIf="currentContract.height === 0">0/10</span>
|
||||
<span *ngIf="currentContract.height !== 0 && (variablesService.height_app - currentContract.height) < 10">{{variablesService.height_app - currentContract.height}}/10</span>
|
||||
<span *ngIf="historyBlock && historyBlock.sortAmount">{{(historyBlock.is_income ? '+' : '') + (historyBlock.sortAmount | intToMoney)}} {{variablesService.defaultCurrency}}</span>
|
||||
<span *ngIf="historyBlock && historyBlock.sortAmount && historyBlock.sortAmount.toString() !== '0'">{{(historyBlock.is_income ? '+' : '') + (historyBlock.sortAmount | intToMoney)}} {{variablesService.defaultCurrency}}</span>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
|
|
@ -188,7 +188,7 @@
|
|||
<!--<button type="button" class="green-button">{{ 'PURCHASE.COMPLETE_BUTTON' | translate }}</button>-->
|
||||
|
||||
<ng-container *ngIf="!currentContract.is_a && currentContract.state == 1">
|
||||
<button type="button" class="blue-button" (click)="acceptState();" [disabled]="(currentContract.private_detailes.b_pledge + ('0.01' | moneyToInt) + ('0.01' | moneyToInt)) > variablesService.currentWallet.unlocked_balance">
|
||||
<button type="button" class="blue-button" (click)="acceptState();" [disabled]="currentContract.private_detailes.b_pledge.plus(('0.01' | moneyToInt)).plus(('0.01' | moneyToInt)).isGreaterThan(variablesService.currentWallet.unlocked_balance)">
|
||||
{{'Accept (Make pledge)' | translate}}
|
||||
</button>
|
||||
<button type="button" class="turquoise-button" (click)="ignoredContract();">{{'Ignore' | translate}}</button>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<div class="sidebar-account" *ngFor="let wallet of variablesService.wallets" [class.active]="wallet?.wallet_id === walletActive" [routerLink]="['/wallet/' + wallet.wallet_id + '/history']">
|
||||
<div class="sidebar-account-row account-title-balance">
|
||||
<span class="title">{{wallet.name}}</span>
|
||||
<span class="balance">{{wallet.unlocked_balance | intToMoney}} {{variablesService.defaultCurrency}}</span>
|
||||
<span class="balance">{{wallet.unlocked_balance | intToMoney : '3' }} {{variablesService.defaultCurrency}}</span>
|
||||
</div>
|
||||
<div class="sidebar-account-row account-alias">
|
||||
<span>{{wallet.alias}}</span>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<div class="header">
|
||||
<div>
|
||||
<h3>{{variablesService.currentWallet.name}}</h3>
|
||||
<button (click)="openInBrowser()">
|
||||
<button (click)="openInBrowser('zano.org')">
|
||||
<i class="icon account"></i>
|
||||
<span>{{ 'WALLET.REGISTER_ALIAS' | translate }}</span>
|
||||
</button>
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
<i class="icon copy" (click)="copyAddress()"></i>
|
||||
</div>
|
||||
<div class="balance">
|
||||
<span>{{variablesService.currentWallet.unlocked_balance | intToMoney}} {{variablesService.defaultCurrency}}</span>
|
||||
<span [tooltip]="getTooltip()" [placement]="'bottom'" [tooltipClass]="'balance-tooltip'" [delay]="500" [timeout]="1000">{{variablesService.currentWallet.balance | intToMoney : '3'}} {{variablesService.defaultCurrency}}</span>
|
||||
<span>$ {{variablesService.currentWallet.getMoneyEquivalent(variablesService.moneyEquivalent) | intToMoney | number : '1.2-2'}}</span>
|
||||
</div>
|
||||
<div class="tabs">
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ import {Component, OnInit, OnDestroy, NgZone} from '@angular/core';
|
|||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
import {BackendService} from '../_helpers/services/backend.service';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {IntToMoneyPipe} from '../_helpers/pipes/int-to-money.pipe';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
|
||||
@Component({
|
||||
selector: 'app-wallet',
|
||||
|
|
@ -61,7 +64,9 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
private router: Router,
|
||||
private backend: BackendService,
|
||||
private variablesService: VariablesService,
|
||||
private ngZone: NgZone
|
||||
private ngZone: NgZone,
|
||||
private translate: TranslateService,
|
||||
private intToMoneyPipe: IntToMoneyPipe
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -90,8 +95,28 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
this.backend.setClipboard(this.variablesService.currentWallet.address);
|
||||
}
|
||||
|
||||
openInBrowser() {
|
||||
this.backend.openUrlInBrowser('zano.org');
|
||||
getTooltip() {
|
||||
const tooltip = document.createElement('div');
|
||||
const available = document.createElement('span');
|
||||
available.setAttribute('class', 'available');
|
||||
available.innerHTML = this.translate.instant('WALLET.AVAILABLE_BALANCE', {available: this.intToMoneyPipe.transform(this.variablesService.currentWallet.unlocked_balance), currency: this.variablesService.defaultCurrency});
|
||||
tooltip.appendChild(available);
|
||||
const locked = document.createElement('span');
|
||||
locked.setAttribute('class', 'locked');
|
||||
locked.innerHTML = this.translate.instant('WALLET.LOCKED_BALANCE', {locked: this.intToMoneyPipe.transform(this.variablesService.currentWallet.balance.minus(this.variablesService.currentWallet.unlocked_balance)), currency: this.variablesService.defaultCurrency});
|
||||
tooltip.appendChild(locked);
|
||||
const link = document.createElement('span');
|
||||
link.setAttribute('class', 'link');
|
||||
link.innerHTML = this.translate.instant('WALLET.LOCKED_BALANCE_LINK');
|
||||
link.addEventListener('click', () => {
|
||||
this.openInBrowser('docs.zano.org/docs/locked-balance');
|
||||
});
|
||||
tooltip.appendChild(link);
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
openInBrowser(link) {
|
||||
this.backend.openUrlInBrowser(link);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
"OLD_PURCHASE": "Purchase"
|
||||
},
|
||||
"SIDEBAR": {
|
||||
"TITLE": "Accounts",
|
||||
"TITLE": "Wallets",
|
||||
"ADD_NEW": "+ Add new",
|
||||
"ACCOUNT": {
|
||||
"STAKING": "Staking",
|
||||
|
|
@ -54,16 +54,16 @@
|
|||
"BUTTON_SELECT": "Select wallet location",
|
||||
"BUTTON_CREATE": "Create wallet",
|
||||
"TITLE_SAVE": "Save the wallet file.",
|
||||
"ERROR_CANNOT_SAVE_TOP": "You cannot record a file on top of another file",
|
||||
"ERROR_CANNOT_SAVE_SYSTEM": "You cannot save a safe file to the system partition"
|
||||
"ERROR_CANNOT_SAVE_TOP": "Existing wallet files cannot be replaced or overwritten",
|
||||
"ERROR_CANNOT_SAVE_SYSTEM": "Wallet files cannot be saved to the OS partition"
|
||||
},
|
||||
"OPEN_WALLET": {
|
||||
"NAME": "Wallet name",
|
||||
"PASS": "Wallet password",
|
||||
"BUTTON": "Open wallet",
|
||||
"WITH_ADDRESS_ALREADY_OPEN": "A wallet with this account is already open",
|
||||
"SAFE_FILE_NOT_FOUND1": "Safe file not found",
|
||||
"SAFE_FILE_NOT_FOUND2": "<br/><br/> It might have been renamed or moved. <br/> To open it, use the \"Open safe\" button."
|
||||
"WITH_ADDRESS_ALREADY_OPEN": "A wallet with this address is already open",
|
||||
"SAFE_FILE_NOT_FOUND1": "Wallet file not found",
|
||||
"SAFE_FILE_NOT_FOUND2": "<br/><br/> It might have been renamed or moved. <br/> To open it, use the \"Open wallet\" button."
|
||||
},
|
||||
"RESTORE_WALLET": {
|
||||
"LABEL_NAME": "Wallet name",
|
||||
|
|
@ -72,18 +72,18 @@
|
|||
"CONFIRM": "Confirm wallet password",
|
||||
"BUTTON_SELECT": "Select wallet location",
|
||||
"BUTTON_CREATE": "Create wallet",
|
||||
"NOT_CORRECT_FILE_OR_PASSWORD": "Invalid safe file or password does not match",
|
||||
"NOT_CORRECT_FILE_OR_PASSWORD": "Invalid wallet file or password does not match",
|
||||
"CHOOSE_PATH": "Please choose a path"
|
||||
},
|
||||
"SEED_PHRASE": {
|
||||
"TITLE": "Make sure to keep your seed phrase in a safe place. If you forget your seed phrase you will not be able to recover your account.",
|
||||
"BUTTON_CREATE_ACCOUNT" : "Create account"
|
||||
"TITLE": "Make sure to keep your seed phrase in a safe place. If you forget your seed phrase you will not be able to recover your wallet.",
|
||||
"BUTTON_CREATE_ACCOUNT" : "Create wallet"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "Settings",
|
||||
"DARK_THEME": "Dark theme",
|
||||
"WHITE_THEME": "White theme",
|
||||
"GRAY_THEME": "Gray theme",
|
||||
"GRAY_THEME": "Grey theme",
|
||||
"MASTER_PASSWORD": {
|
||||
"TITLE": "Update master password",
|
||||
"OLD": "Old password",
|
||||
|
|
@ -96,6 +96,9 @@
|
|||
"REGISTER_ALIAS": "Register an alias",
|
||||
"DETAILS": "Details",
|
||||
"LOCK": "Lock",
|
||||
"AVAILABLE_BALANCE": "Available <b>{{available}} {{currency}}<b/>",
|
||||
"LOCKED_BALANCE": "Locked <b>{{locked}} {{currency}}<b/>",
|
||||
"LOCKED_BALANCE_LINK": "What does that mean?",
|
||||
"TABS": {
|
||||
"SEND": "Send",
|
||||
"RECEIVE": "Receive",
|
||||
|
|
@ -121,7 +124,7 @@
|
|||
"MIXIN": "Mixin",
|
||||
"FEE": "Fee",
|
||||
"BUTTON": "Send",
|
||||
"SUCCESS_SENT": "The payment will be received within 20 minutes"
|
||||
"SUCCESS_SENT": "Transaction sent"
|
||||
},
|
||||
"HISTORY": {
|
||||
"STATUS": "Status",
|
||||
|
|
@ -131,7 +134,16 @@
|
|||
"DATE": "Date",
|
||||
"AMOUNT": "Amount",
|
||||
"FEE": "Fee",
|
||||
"ADDRESS": "Address"
|
||||
"ADDRESS": "Address",
|
||||
"DETAILS": {
|
||||
"ID": "Transaction ID",
|
||||
"SIZE": "Transaction size",
|
||||
"SIZE_VALUE": "{{value}} bytes",
|
||||
"HEIGHT": "Height",
|
||||
"CONFIRMATION": "Confirmation",
|
||||
"INPUTS": "Inputs",
|
||||
"OUTPUTS": "Outputs"
|
||||
}
|
||||
},
|
||||
"CONTRACTS": {
|
||||
"EMPTY": "No active contracts.",
|
||||
|
|
@ -175,13 +187,13 @@
|
|||
"PROGRESS_COMPLETE": "Completed",
|
||||
"FEE": "Fee",
|
||||
"PAYMENT": "Payment ID",
|
||||
"ACCEPT_STATE_WAIT_BIG": "You have accepted the contract proposal. Please wait for the pledges to be made",
|
||||
"ACCEPT_STATE_WAIT_BIG": "You have accepted the contract proposal. Please wait for the deposits to be made",
|
||||
"IGNORED_ACCEPT": "You have ignored the contract proposal",
|
||||
"BURN_PROPOSAL": "The pledges have been nullified.",
|
||||
"BURN_PROPOSAL": "The deposits have been voided.",
|
||||
"SUCCESS_FINISH_PROPOSAL": "The contract is complete. The payment has been sent.",
|
||||
"SEND_CANCEL_PROPOSAL": "Proposal to cancel contract sent to seller",
|
||||
"IGNORED_CANCEL": "You have ignored the proposal to cancel the contract",
|
||||
"DEALS_CANCELED_WAIT": "The contract is being cancelled. Please wait for the pledge to be returned",
|
||||
"DEALS_CANCELED_WAIT": "The contract is being cancelled. Please wait for the deposit to be returned",
|
||||
"WAITING_TIME": "Time until response"
|
||||
},
|
||||
"MESSAGES": {
|
||||
|
|
@ -194,18 +206,18 @@
|
|||
"NOT_ENOUGH_MONEY": "Insufficient funds in account",
|
||||
"CORE_BUSY": "Internal error (core is busy)",
|
||||
"DAEMON_BUSY": "Internal error: deamon is busy",
|
||||
"NO_MONEY_REMOVE_OFFER": "There is no fee for deleting an offer, but in order to protect the network against flood transactions you need to have at least {{fee}} {{currency}} in your safe",
|
||||
"NO_MONEY_REMOVE_OFFER": "There is no fee for deleting an offer, but in order to protect the network against flood transactions you need to have at least {{fee}} {{currency}} in your wallet",
|
||||
"NOT_ENOUGH_OUTPUTS_TO_MIX": "For the sake of security, mixed transaction will take several days",
|
||||
"TRANSACTION_IS_TO_BIG": "This transaction is large and was therefore denied by the network. Try sending the required amount in parts.",
|
||||
"TRANSFER_ATTEMPT": "There is no connection to the Zano network",
|
||||
"TRANSACTION_IS_TO_BIG": "Transaction exceeds network limit, send required amount with multiple transactions",
|
||||
"TRANSFER_ATTEMPT": "There is no connection to Zano network",
|
||||
"ACCESS_DENIED": "Access denied",
|
||||
"TRANSACTION_ERROR": "Error. Payment not completed.",
|
||||
"TRANSACTION_ERROR": "Error. Transaction not completed.",
|
||||
"BAD_ARG": "Invalid argument",
|
||||
"WALLET_WRONG_ID": "Invalid wallet ID",
|
||||
"WRONG_PASSWORD": "Invalid password",
|
||||
"FILE_RESTORED": "The safe file was corrupted somehow. We have recovered the keys and safe from the blockchain.",
|
||||
"FILE_RESTORED": "The wallet file was corrupted. We have recovered the keys and the wallet from the blockchain",
|
||||
"FILE_NOT_FOUND": "File not found",
|
||||
"FILE_EXIST": "A file with that name already exists. Enter another name to save the file under",
|
||||
"FILE_NOT_SAVED": "You cannot save a safe file in this folder. Please choose another folder."
|
||||
"FILE_NOT_SAVED": "You cannot save a wallet file in this folder. Please choose another folder."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,52 +385,55 @@ input[type='checkbox'].style-checkbox {
|
|||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
.balance-tooltip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 1.3rem;
|
||||
padding: 1.3rem;
|
||||
|
||||
@include themify($themes) {
|
||||
background: themed(modalBackground);
|
||||
background: themed(tooltipBackgroundColor);
|
||||
box-shadow: themed(tooltipShadow);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
.content {
|
||||
&.ng-tooltip-top {
|
||||
margin-top: -1rem;
|
||||
}
|
||||
|
||||
.icon.error {
|
||||
&.ng-tooltip-bottom {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(redTextColor);
|
||||
}
|
||||
}
|
||||
&.ng-tooltip-left {
|
||||
margin-left: -1rem;
|
||||
}
|
||||
|
||||
.icon.success {
|
||||
&.ng-tooltip-right {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(greenTextColor);
|
||||
}
|
||||
}
|
||||
.available {
|
||||
margin-bottom: 1.7rem;
|
||||
|
||||
.icon.info {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
b {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.action-button {
|
||||
.locked {
|
||||
margin-bottom: 0.7rem;
|
||||
|
||||
b {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
cursor: pointer;
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
color: themed(alternativeTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(closeButtonColor);
|
||||
}
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -472,3 +475,93 @@ input[type='checkbox'].style-checkbox {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
app-modal-container {
|
||||
|
||||
.modal {
|
||||
|
||||
@include themify($themes) {
|
||||
background: themed(modalBackground);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
.icon.error {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(redTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.icon.success {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(greenTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.icon.info {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-button {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
color: themed(alternativeTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(closeButtonColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app-transaction-details {
|
||||
|
||||
.table {
|
||||
|
||||
@include themify($themes) {
|
||||
border-top: 0.2rem solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
|
||||
.row {
|
||||
|
||||
.cell {
|
||||
|
||||
&.label {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(optionalTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
&.value {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
&.key-value {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,34 @@ app-history {
|
|||
|
||||
tr {
|
||||
|
||||
&:nth-child(4n+1) {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(tableBackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(4n+2) {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(tableBackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(4n+3) {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(4n+4) {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
|
||||
.confirmation {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,13 @@ int main(int argc, char *argv[])
|
|||
|
||||
epee::string_tools::set_module_name_and_folder(argv[0]);
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1910
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //HiDPI pixmaps
|
||||
qputenv("QT_SCALE_FACTOR", "0.75");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QApplication app(argc, argv);
|
||||
MainWindow viewer;
|
||||
if (!viewer.init_backend(argc, argv))
|
||||
|
|
|
|||
|
|
@ -1061,7 +1061,8 @@ namespace nodetool
|
|||
ce.time_started = cntxt.m_started;
|
||||
ce.last_recv = cntxt.m_last_recv;
|
||||
ce.last_send = cntxt.m_last_send;
|
||||
ce.version = cntxt.m_remote_version;
|
||||
std::strncpy(ce.version, cntxt.m_remote_version.c_str(), std::min(sizeof(ce.version), cntxt.m_remote_version.size()));
|
||||
ce.version[sizeof(ce.version) - 1] = 0; //null terminating just to be sure
|
||||
rsp.connections_list.push_back(ce);
|
||||
return true;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ namespace nodetool
|
|||
time_t last_seen;
|
||||
};
|
||||
|
||||
#define P2P_CONNECTION_ENTRY_VERSION_MAX_SIZE 50
|
||||
|
||||
struct connection_entry
|
||||
{
|
||||
net_address adr;
|
||||
|
|
@ -41,7 +43,7 @@ namespace nodetool
|
|||
uint64_t time_started;
|
||||
uint64_t last_recv;
|
||||
uint64_t last_send;
|
||||
std::string version;
|
||||
char version[P2P_CONNECTION_ENTRY_VERSION_MAX_SIZE];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
|
|
|||
|
|
@ -1225,6 +1225,7 @@ namespace currency
|
|||
std::string cumulative_diff_precise;
|
||||
std::string difficulty;
|
||||
std::string prev_id;
|
||||
std::string pow_seed;
|
||||
uint64_t type;
|
||||
bool is_orphan;
|
||||
uint64_t already_generated_coins;
|
||||
|
|
@ -1249,6 +1250,7 @@ namespace currency
|
|||
KV_SERIALIZE(penalty)
|
||||
KV_SERIALIZE(id)
|
||||
KV_SERIALIZE(prev_id)
|
||||
KV_SERIALIZE(pow_seed)
|
||||
KV_SERIALIZE(cumulative_diff_adjusted)
|
||||
KV_SERIALIZE(cumulative_diff_precise)
|
||||
KV_SERIALIZE(difficulty)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue