Compare commits

..
10 Commits
Author SHA1 Message Date
pharpend 422fccfa88 [broken] jr: add spend feature
It does not work right now, and the blocker right now is that the public node
has debug endpoints turned off. No idea if it would work if said endpoints were
turned on.
2024-03-20 02:41:34 -06:00
pharpend 2ed9a60216 jr: showing balance works 2024-03-20 01:30:00 -06:00
pharpend 89a11bfe48 jr: show balances in popup window (might work?) 2024-03-20 01:09:55 -06:00
pharpend 46263f7c86 jr: version bump 2024-03-20 00:45:57 -06:00
pharpend 708b4bc612 jr: gajumaru color scheme 2024-03-20 00:44:09 -06:00
pharpend aab6f34ba6 jr: version bump 2024-03-20 00:04:47 -06:00
pharpend f9d7ea14be jr: make confirm windows slightly less cancerous 2024-03-19 23:57:22 -06:00
pharpend feac310ef1 make confirm dialog a more pleasant size 2024-03-19 22:59:33 -06:00
pharpend 402c758f0a version bump 2024-03-19 22:59:07 -06:00
pharpend 4be9626a43 jr: network id switching seems to work
todo: change explorer links based on network id
2024-03-19 17:59:20 -06:00
7 changed files with 606 additions and 75 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{type, library}. {type, library}.
{realm, local}. {realm, local}.
{name, jrx}. {name, jrx}.
{version, "0.1.2"}. {version, "0.1.5"}.
{deps, ["local-tweetnacl-1.0.3", {deps, ["local-tweetnacl-1.0.3",
"local-awcp-0.2.3", "local-awcp-0.2.3",
"local-vdk_aecrypt-0.1.2", "local-vdk_aecrypt-0.1.2",
+2 -2
View File
@@ -1,13 +1,13 @@
{"manifest_version" : 3, {"manifest_version" : 3,
"name" : "Jack Russell", "name" : "Jack Russell",
"version" : "0.1.2", "version" : "0.1.5",
"description" : "Browser wallet extension for Aeternity", "description" : "Browser wallet extension for Aeternity",
"icons" : {"48" : "art/jrx-icon-48.png", "icons" : {"48" : "art/jrx-icon-48.png",
"96" : "art/jrx-icon-96.png"}, "96" : "art/jrx-icon-96.png"},
"content_scripts" : [{"matches" : ["*://*/*"], "content_scripts" : [{"matches" : ["*://*/*"],
"js" : ["dist/content.js"]}], "js" : ["dist/content.js"]}],
"action" : {"default_icon" : "art/jrx-icon-32.png", "action" : {"default_icon" : "art/jrx-icon-32.png",
"default_title" : "Jæck Russell", "default_title" : "Jack Russell (Gajumaru Wallet)",
"default_popup" : "pages/popup.html"}, "default_popup" : "pages/popup.html"},
"background" : {"page" : "pages/background.html"}, "background" : {"page" : "pages/background.html"},
"permissions" : ["storage", "scripting"], "permissions" : ["storage", "scripting"],
+19
View File
@@ -0,0 +1,19 @@
:root {
--b1: #FBFCFB;
--b2: #D6DAD8;
--b3: #B9BCb9;
--b4: #969A98;
--b5: #7C7C7C;
--b6: #545454;
--b7: #343434;
--b8: #0A0B0A;
--g1: #c1d8c5;
--g2: #9ab6a1;
--g3: #88a28d;
--g4: #607e68;
--g5: #41664b;
--g6: #345c3e;
--g7: #224d2d;
--g8: #0a2f14;
}
+48 -6
View File
@@ -4,16 +4,58 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<style type="text/css">
html, body {
background-color: #FBFCFB;
font-family: monospace, sans-serif;
font-size: '0.7em';
height: 78%;
}
pre {
background-color: #EBECEB;
overflow: scroll;
box-sizing: border-box;
width: 100%;
height: 100%;
border: 1px solid #ccc;
border-radius: 5px;
padding: 3px;
}
#miscinfo-wrapper1 {
flex: 1 1 auto;
height: 100%;
}
#miscinfo-wrapper3 {
display: flex;
flex-flow: column;
height: 100%;
}
#title-h1 {
text-align: center;
}
</style>
</head> </head>
<body> <body>
<h1 id="title-h1"></h1> <h3 id="title-h1"></h3>
<pre id="miscinfo"></pre> <div>
<button id="good">Yes</button>
<span width="1em">
<button id="bad">No</button>
</div>
<!-- dumbass css hack: https://www.w3docs.com/snippets/html/how-to-make-a-div-fill-the-height-of-the-remaining-space.html -->
<div id='miscinfo-wrapper3'>
<div id='miscinfo-wrapper1'>
<pre id="miscinfo">
</pre>
</div>
</div>
<br>
<button id="good">Yes</button>
<br>
<button id="bad">No</button>
<script type="module" src="./gb.js"></script> <script type="module" src="./gb.js"></script>
+90 -13
View File
@@ -3,17 +3,59 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<style type="text/css"> <style type="text/css">
@import "gaju-colors.css";
body { body {
background: #d6efff; background: var(--b1);
color: --var(g8);
width: 400px; width: 400px;
font-family: monospace, sans-serif; font-family: monospace, sans-serif;
font-size: 0.7em;
}
#jr-hdr {
border: 2px solid var(--g4);
border-radius: 5px;
width: 100%;
background: var(--g2);
}
.psection {
background: var(--b2);
border: 1px solid var(--g4);
border-radius: 5px;
width: 97%;
padding: 5px;
margin-top: 5px;
}
.account-active {
background: var(--g1);
color: var(--g7);
}
.account-inactive {
background: var(--b4);
color: var(--b7);
}
.balance-found {
color: var(--g5);
}
.balance-not-found {
color: var(--b7);
}
a {
color: var(--g5);
} }
</style> </style>
</head> </head>
<body> <body>
<table width="100%" style="background: #dad1ff; border: 2px solid #6c5d96; border-radius: 5px;"> <table id="jr-hdr">
<tr> <tr>
<td><img src="../art/jrx-icon-48.png" style="width: 32px; height: 32px;"></td> <td><img src="../art/jrx-icon-48.png" style="width: 32px; height: 32px;"></td>
<td style="font-size: 32px; text-align: center; font-weight: bold"> <td style="font-size: 32px; text-align: center; font-weight: bold">
@@ -22,7 +64,7 @@
</tr> </tr>
</table> </table>
<div style="margin-top: 5px; width: 95%; background: #d9ffd6; border: 1px solid #6c5d96; border-radius: 5px; padding: 5px;"> <div class="psection">
<table > <table >
<tr> <tr>
<td><img src="../art/keypair.svg" style="width: 32px; height: 32px;"></td> <td><img src="../art/keypair.svg" style="width: 32px; height: 32px;"></td>
@@ -44,8 +86,8 @@
</div> </div>
<!-- generate new keypair --> <!-- generate new keypair -->
<div style="margin-top: 5px; width: 95%; background: #d6ffd9; border: 1px solid #6c5d96; border-radius: 5px; padding: 5px;"> <div class="psection">
<table > <table >
<tr> <tr>
<td><img src="../art/keypair.svg" style="width: 32px; height: 32px;"></td> <td><img src="../art/keypair.svg" style="width: 32px; height: 32px;"></td>
@@ -61,8 +103,9 @@
<button id="generate-btn">Generate New Keypair</button> <button id="generate-btn">Generate New Keypair</button>
</form> </form>
</div> </div>
<!-- faert recovery --> <!-- faert recovery -->
<div style="margin-top: 5px; width: 95%; background: #ffd6d9; border: 1px solid #6c5d96; border-radius: 5px; padding: 5px;"> <div class="psection">
<table > <table >
<tr> <tr>
<td><img src="../art/keypair.svg" style="width: 32px; height: 32px;"></td> <td><img src="../art/keypair.svg" style="width: 32px; height: 32px;"></td>
@@ -81,15 +124,49 @@
<br> <br>
<button id="faert-btn">Recover Keypair from GajuPhrase</button> <button id="faert-btn">Recover Keypair from GajuPhrase</button>
</form> </form>
<!-- recover from seed phrase
<form>
<label for="seed-input">Seed Phrase:</label>
<input id="seed-input"></input>
<button id="seed-btn">Recover Keypair from Seed Phrase</button>
</form>
-->
</div> </div>
<!-- network id -->
<div class="psection">
<table >
<tr>
<td><img src="../art/keypair.svg" style="width: 32px; height: 32px;"></td>
<td style="justify-content: center; font-size: 28px; text-align: center; font-weight: bold">
NETWORK ID
</td>
</tr>
</table>
<form id='netids'></form>
</div>
<!-- spend -->
<div class="psection">
<table >
<tr>
<td><img src="../art/keypair.svg" style="width: 32px; height: 32px;"></td>
<td style="justify-content: center; font-size: 28px; text-align: center; font-weight: bold">
SEND SOMEONE MONEY
</td>
</tr>
</table>
<form id="spend-params">
<label for="spend-recipient">Recipient Address:</label>
<input id="spend-recipient"></input>
<br>
<label for="spend-amount">Amount (gattos):</label>
<input id="spend-amount"></input>
<br>
<button type="button" id="spend-btn">Send</button>
</form>
<p id='spend-result'></p>
</div>
<pre id="scratch"></pre> <pre id="scratch"></pre>
<!-- <!--
+107 -7
View File
@@ -75,6 +75,7 @@ export {
p_delete_key, p_delete_key,
p_get_gphrase, p_get_gphrase,
p_gphrase_recover, p_gphrase_recover,
p_netid_switch,
// background script api // background script api
b_main b_main
}; };
@@ -85,6 +86,10 @@ let GB_ITERS = 1;
let GB_SEC = 200*GB_ITERS; // [ITER]; 1iter / 5ms = 200iter / sec let GB_SEC = 200*GB_ITERS; // [ITER]; 1iter / 5ms = 200iter / sec
let GB_MIN = 60*GB_SEC; // [ITER] let GB_MIN = 60*GB_SEC; // [ITER]
// size of confirm windows
let GB_W_PX = 500;
let GB_H_PX = 300;
let MSG_SIGN_TIMEOUT = 30*GB_MIN; let MSG_SIGN_TIMEOUT = 30*GB_MIN;
let TX_SIGN_TIMEOUT = 30*GB_MIN; let TX_SIGN_TIMEOUT = 30*GB_MIN;
@@ -97,6 +102,7 @@ let NETIDS_ALT_DEF : Array<bi_netid> = [NETID_AETEST, NETID_AEMAIN];
let NETIDS_ALL : Array<bi_netid> = [NETID_GDEV, NETID_AETEST, NETID_AEMAIN]; let NETIDS_ALL : Array<bi_netid> = [NETID_GDEV, NETID_AETEST, NETID_AEMAIN];
//============================================================================= //=============================================================================
//============================================================================= //=============================================================================
// API: GLOBAL TYPES // API: GLOBAL TYPES
@@ -243,6 +249,18 @@ p_gphrase_recover
name : name}}}) as void; name : name}}}) as void;
} }
async function
p_netid_switch
(new_netid : string)
: Promise<void>
{
console.log('b_lib p_netid_switch', {new_netid: new_netid});
return await browser.runtime.sendMessage({frum: 'popup',
data: {method : 'p_netid_switch',
args : {new_netid : new_netid}}}) as void;
}
//============================================================================= //=============================================================================
//============================================================================= //=============================================================================
// API: BACKGROUND SCRIPT // API: BACKGROUND SCRIPT
@@ -483,7 +501,7 @@ bi_msg_handler_content
case "connection.open": case "connection.open":
return w2a_ok({id : "jr", return w2a_ok({id : "jr",
name : "JR", name : "JR",
networkId : "gajumaru_devnet", networkId : i_state.netid_cur,
origin : browser.runtime.getURL('/'), origin : browser.runtime.getURL('/'),
type : "extension"}); type : "extension"});
@@ -514,13 +532,13 @@ bi_msg_handler_content
console.log('jr bg content message handler transaction sign'); console.log('jr bg content message handler transaction sign');
let tx_str : string = msg.data.params.tx; let tx_str : string = msg.data.params.tx;
console.log('transaction: ', tx_str); console.log('transaction: ', tx_str);
let result = await tx_sign(tx_str, secret_key) let result = await tx_sign(i_state.netid_cur, tx_str, secret_key)
if if
('good' === result.result) { ('good' === result.result) {
return w2a_ok({signedTransaction: result.signedTransaction}); return w2a_ok({signedTransaction: result.signedTransaction});
} }
else { else {
return w2a_err(awcp.ERROR_CODE_RpcRejectedByUserError, "your not pretty enough"); return w2a_err(awcp.ERROR_CODE_RpcRejectedByUserError, "user rejected tx");
} }
//if (result.result === 'good') { //if (result.result === 'good') {
// return w2a_ok({signedTransaction: result.signedTransaction}); // return w2a_ok({signedTransaction: result.signedTransaction});
@@ -701,7 +719,8 @@ msg_sign
*/ */
async function async function
tx_sign tx_sign
(tx_str : string, (netid_cur : bi_netid,
tx_str : string,
secret_key : Uint8Array) secret_key : Uint8Array)
: Promise< {result : 'good', : Promise< {result : 'good',
signedTransaction : string} signedTransaction : string}
@@ -722,8 +741,7 @@ tx_sign
// we sign <<NetworkId, SerializedObject>> // we sign <<NetworkId, SerializedObject>>
// SerializedObject can either be the object or the hash of the object // SerializedObject can either be the object or the hash of the object
// let's stick with hash for now // let's stick with hash for now
// FIXME: get network id from application state let network_id : Uint8Array = vdk_binary.encode_utf8(netid_cur);
let network_id : Uint8Array = vdk_binary.encode_utf8('gajumaru_devnet');
// let tx_hash_bytes : Uint8Array = hash(tx_bytes); // let tx_hash_bytes : Uint8Array = hash(tx_bytes);
let sign_data : Uint8Array = vdk_binary.bytes_concat(network_id, tx_bytes); let sign_data : Uint8Array = vdk_binary.bytes_concat(network_id, tx_bytes);
// @ts-ignore yes nacl is stupid // @ts-ignore yes nacl is stupid
@@ -834,7 +852,9 @@ gb
// does the user want to sign the message // does the user want to sign the message
let confirm_window = await browser.windows.create({url : '../pages/gb.html', let confirm_window = await browser.windows.create({url : '../pages/gb.html',
type : 'popup'}); type : 'popup',
width : GB_W_PX,
height : GB_H_PX});
// @ts-ignore shut the fuck up // @ts-ignore shut the fuck up
let tabid : number = confirm_window.tabs[0].id; let tabid : number = confirm_window.tabs[0].id;
@@ -990,6 +1010,7 @@ type bi_popup_calldata
| bi_pc_p_delete_key | bi_pc_p_delete_key
| bi_pc_p_get_gphrase | bi_pc_p_get_gphrase
| bi_pc_p_gphrase_recover | bi_pc_p_gphrase_recover
| bi_pc_p_netid_switch
; ;
type bi_pc_p_get_data type bi_pc_p_get_data
@@ -1021,6 +1042,10 @@ type bi_pc_p_gphrase_recover
args : {gphrase : string, args : {gphrase : string,
name : string}}; name : string}};
type bi_pc_p_netid_switch
= {method : 'p_netid_switch',
args : {new_netid : string}};
type bi_popup_return_data type bi_popup_return_data
= p_data = p_data
@@ -1058,6 +1083,8 @@ bi_msg_handler_popup
return await bi_p_get_gphrase(msg.args); return await bi_p_get_gphrase(msg.args);
case 'p_gphrase_recover': case 'p_gphrase_recover':
return await bi_p_gphrase_recover(msg.args); return await bi_p_gphrase_recover(msg.args);
case 'p_netid_switch':
return await bi_p_netid_switch(msg.args);
default: default:
throw new Error('unsupported popup call method'); throw new Error('unsupported popup call method');
} }
@@ -1361,6 +1388,79 @@ bi_p_gphrase_recover
async function
bi_p_netid_switch
(args: {new_netid : string})
: Promise<void>
{
console.log('b_lib bi_p_netid_switch', {new_netid: args.new_netid});
// get state
let istate : bi_state = await bi_get_state();
// type bi_state
// = {rich_keypairs : Array<bi_rich_keypair>,
// netid_cur : bi_netid,
// netids_alt : Array<bi_netid>};
//
// let NETIDS_ALL : Array<bi_netid> = [NETID_GDEV, NETID_AETEST, NETID_AEMAIN];
// if this is already the network id, do nothing
if
(istate.netid_cur === args.new_netid)
return;
// next make sure it's allowed
else if
(!elem(args.new_netid, NETIDS_ALL))
throw new Error('invalid network id: ' + args.new_netid);
// ok now we know we're definitely switching to a valid network id
else {
// set the current network id to the one the user asked for
istate.netid_cur = args.new_netid as bi_netid;
// new alts are all of them minus the new current one
istate.netids_alt = exclude(args.new_netid, NETIDS_ALL) as Array<bi_netid>;
await bi_set_state(istate);
}
}
function
elem
<t>
(item : t,
list : Array<t>)
: boolean
{
for (let im of list)
if (item === im)
return true;
return false;
}
function
exclude
<t>
(item : t,
list : Array<t>)
: Array<t>
{
// accumulator
let new_list : Array<t> = [];
for (let im of list) {
if (im === item)
continue;
else
new_list.push(im);
}
return new_list;
}
//============================================================================= //=============================================================================
//============================================================================= //=============================================================================
+338 -45
View File
@@ -6,6 +6,10 @@ import * as b_lib from './b_lib.js';
p_main(); p_main();
let EXPLORER_URL = 'https://explorer.qpq.swiss';
let active_account_next_nonce = 0;
/** /**
* runs whenever the popup opens * runs whenever the popup opens
* *
@@ -33,6 +37,8 @@ p_main
console.log('popup main'); console.log('popup main');
await pi_repop(); await pi_repop();
let pdata = await b_lib.p_get_data();
// add unique name for default // add unique name for default
let unique_name: string = await b_lib.p_get_unique_name(); let unique_name: string = await b_lib.p_get_unique_name();
@@ -42,6 +48,7 @@ p_main
document.getElementById('faert-name')!.value = unique_name; document.getElementById('faert-name')!.value = unique_name;
// add hooks for each button // add hooks for each button
// for generating new keypair
let onclick_generate = let onclick_generate =
async function () { async function () {
console.log('popup p_main onclick_generate'); console.log('popup p_main onclick_generate');
@@ -69,6 +76,89 @@ p_main
document document
.getElementById('faert-btn')! .getElementById('faert-btn')!
.addEventListener('click', onclick_gphrase); .addEventListener('click', onclick_gphrase);
// spend
let onclick_spend =
async function () {
console.log('onclick_spend');
// grab recipient address
// @ts-ignore fuck off it's my website
let recip_address = document.getElementById('spend-recipient').value;
// grab recipient amount and parse
// @ts-ignore fuck off it's my website
let amount = parseInt(document.getElementById('spend-amount').value);
let source = active_account(pdata);
console.log('onclick_spend params', {recipient: recip_address, amount: amount, source: source});
// hack
if ('' === source) {
console.log('onclick_spend no active key');
// HACK: otherwise populate field with no key
let spend_result_p = document.getElementById('spend-result')!;
spend_result_p.innerHTML = 'ERROR: no active key';
}
else {
let maybe_hash = await do_spend(source, recip_address, amount);
console.log('onclick_spend maybe_hash', maybe_hash);
if (maybe_hash.ok) {
// @ts-ignore fuck off
let tx_hash = maybe_hash.tx_hash;
// @ts-ignore fuck off
let spend_result_p = document.getElementById('spend-result')!;
let spend_result_a = document.createElement('a')!;
spend_result_a.href = EXPLORER_URL + '/transactions/' + tx_hash;
spend_result_a.innerHTML = tx_hash;
spend_result_p.appendChild(spend_result_a);
}
else {
// @ts-ignore fuck off
let reason = maybe_hash.reason;
let spend_result_p = document.getElementById('spend-result')!;
spend_result_p.innerHTML = 'ERROR: ' + reason;
}
}
};
document
.getElementById('spend-btn')!
.addEventListener('click', onclick_spend);
}
function
active_account
(pdata: b_lib.p_data)
: string
{
// type p_data
// = {rich_pubkeys: Array<p_rich_pubkey>,
// netid_cur : string,
// netids_alt : Array<string>};
// type p_rich_pubkey
// = {akstr : string,
// active : boolean,
// name : string};
for (let rkp of pdata.rich_pubkeys) {
if (rkp.active)
return rkp.akstr;
}
return '';
}
// kill all the children
function
pfizer
(elt : HTMLElement)
: void
{
// from: https://www.geeksforgeeks.org/remove-all-the-child-elements-of-a-dom-node-in-javascript/
// kill the last child repeatedly
let child = elt.lastElementChild;
while (child) {
elt.removeChild(child);
child = elt.lastElementChild;
}
} }
@@ -84,26 +174,68 @@ pi_repop
let popup_data: b_lib.p_data = await b_lib.p_get_data(); let popup_data: b_lib.p_data = await b_lib.p_get_data();
console.log('popup pi_repop popup_data', popup_data); console.log('popup pi_repop popup_data', popup_data);
// network ids
// grab the relevent element
let netid_form = document.getElementById('netids')!;
// eliminate children
pfizer(netid_form);
// add radio button for current network id
let netid_cur_input = document.createElement('input');
netid_cur_input.setAttribute('type', 'radio');
netid_cur_input.setAttribute('value', popup_data.netid_cur);
netid_cur_input.setAttribute('id', 'r-' + popup_data.netid_cur);
netid_cur_input.checked = true;
let netid_cur_label = document.createElement('label');
netid_cur_label.setAttribute('for', 'r-' + popup_data.netid_cur);
netid_cur_label.innerHTML = popup_data.netid_cur;
// add elements to form
netid_form.appendChild(netid_cur_input);
netid_form.appendChild(netid_cur_label);
// add alt ids
for (let netid_alt of popup_data.netids_alt) {
// add brs here
netid_form.appendChild(document.createElement('br'));
// add radio button for this network id
let netid_alt_input = document.createElement('input');
netid_alt_input.setAttribute('type', 'radio');
netid_alt_input.setAttribute('value', netid_alt);
netid_alt_input.setAttribute('id', 'r-' + netid_alt);
let netid_alt_label = document.createElement('label');
netid_alt_label.setAttribute('for', 'r-' + netid_alt);
netid_alt_label.innerHTML = netid_alt;
// add elements to form
netid_form.appendChild(netid_alt_input);
netid_form.appendChild(netid_alt_label);
// function to call background script
let switchnet =
async function() {
await b_lib.p_netid_switch(netid_alt);
pi_repop();
};
// add netid switch things
netid_alt_input.onclick = switchnet;
netid_alt_label.onclick = switchnet;
}
// show keypairs // show keypairs
// step 1: delete the existing list of keypairs // step 1: delete the existing list of keypairs
let kill_all_children =
function (elt : HTMLElement) {
// from: https://www.geeksforgeeks.org/remove-all-the-child-elements-of-a-dom-node-in-javascript/
// kill the last child repeatedly
let child = elt.lastElementChild;
while (child) {
elt.removeChild(child);
child = elt.lastElementChild;
}
};
// get the ul // get the ul
let pubkeys_ul = document.getElementById('keypairs')!; let pubkeys_ul = document.getElementById('keypairs')!;
// delete the existing list of keypairs // delete the existing list of keypairs
// we will repopulate it in a minute // we will repopulate it in a minute
// this isn't necessary right now but in the future we will add a delete // this isn't necessary right now but in the future we will add a delete
// keypair function so this is prophylaxis // keypair function so this is prophylaxis
kill_all_children(pubkeys_ul); pfizer(pubkeys_ul);
// type p_data // type p_data
// = {rich_pubkeys: Array<p_rich_pubkey>}; // = {rich_pubkeys: Array<p_rich_pubkey>};
@@ -150,6 +282,49 @@ pi_repop
// add // add
addr_li.appendChild(addr_a); addr_li.appendChild(addr_a);
// balance
let bal_li = document.createElement('li');
bal_li.innerHTML += 'Balance: ';
// old school async/await
pi_balance(this_rkp.akstr).then(
function(maybe_balance) {
// if there is a balance, show it in green
// also make nonce nonce if account is active
if (maybe_balance.ok)
{
if (this_rkp.active) {
// @ts-ignore fuck off i know what i'm doing
let nonce = maybe_balance.nonce;
active_account_next_nonce = nonce;
}
let greentext = document.createElement('span');
greentext.classList.add('balance-found');
// @ts-ignore fuck off i know what i'm doing
greentext.innerHTML = '' + maybe_balance.balance;
bal_li.appendChild(greentext);
}
// if not, show reason and make it red
// also make nonce 0 if account is active
else
{
if (this_rkp.active) {
active_account_next_nonce = 0;
}
let redtext = document.createElement('span');
redtext.classList.add('balance-not-found');
// @ts-ignore fuck off i know what i'm doing
redtext.innerHTML = '' + maybe_balance.reason;
bal_li.appendChild(redtext);
}
}
);
// add delete button // add delete button
let del_li = document.createElement('li'); let del_li = document.createElement('li');
@@ -187,19 +362,20 @@ pi_repop
// add everything inside-out // add everything inside-out
rkp_ul.appendChild(addr_li);
rkp_ul.appendChild(name_li); rkp_ul.appendChild(name_li);
rkp_ul.appendChild(del_li); rkp_ul.appendChild(addr_li);
rkp_ul.appendChild(bal_li);
rkp_ul.appendChild(gphrase_li); rkp_ul.appendChild(gphrase_li);
rkp_ul.appendChild(del_li);
this_li.appendChild(rkp_ul); this_li.appendChild(rkp_ul);
// if active, make background green // if active, make background "active"
if (this_rkp.active) if (this_rkp.active)
this_li.style.background = 'green'; this_li.classList.add('account-active');
// otherwise make background red and add activate li // otherwise make background "inactive" and add activate li
else { else {
this_li.style.background = 'red'; this_li.classList.add('account-inactive');
let activate_li = document.createElement('li'); let activate_li = document.createElement('li');
let activate_a = document.createElement('a'); let activate_a = document.createElement('a');
activate_a.innerHTML = 'Switch to this key'; activate_a.innerHTML = 'Switch to this key';
@@ -223,36 +399,116 @@ pi_repop
} }
/**
* shorten the ak_... str
*/
function
pi_shakstr
(akstr : string)
: string
{
console.log('popup shakstr');
return akstr.slice(0, 10) + '...';
}
/**
* get account balance of ak_... str
*/
async function async function
pi_balance do_spend
(akstr : string) (source : string,
recipient : string,
amount : number)
: Promise< {ok : true, : Promise< {ok : true,
balance : number} tx_hash : string}
| {ok : false, | {ok : false,
reason : string} reason : string}
> >
{ {
let endpoint_init_url = 'http://demonet.qpq.swiss:3013'; console.log('popup do_spend', {source: source, recipient: recipient, amount: amount});
let this_endpoint = endpoint_init_url + '/accounts/' + akstr; let maybe_spendtx = await mk_spend(source, recipient, amount);
let input_params = {pubkey: akstr}; if (maybe_spendtx.ok) {
return await post_spend(maybe_spendtx.tx);
}
else {
// @ts-ignore fuck off
return maybe_spendtx;
}
}
async function
post_spend
(tx: string)
: Promise< {ok : true,
tx_hash : string}
| {ok : false,
reason : string}
>
{
console.log('popup post_spend', tx);
let req_obj = {tx: tx};
let req_body = JSON.stringify(req_obj, undefined, 4);
let endpoint_init_url = 'https://demonet.qpq.swiss/v2';
let this_endpoint = endpoint_init_url + '/transactions';
// fetch: https://developer.mozilla.org/en-US/docs/Web/API/fetch
let response = await fetch(this_endpoint, {method: 'POST', body: req_body});
let return_data = await response.json();
console.log('popup post_spend return data', return_data);
// 200 = ok
// 400 = bad tx
switch (response.status) {
case 200:
// get the hash
// @ts-ignore talking to foreign api
return {ok: true, tx_hash: return_data.tx_hash};
// wtf
default:
// @ts-ignore talking to foreign api
return {ok: false, reason: return_data.reason};
}
}
let MIN_FEE = 17000;
async function
mk_spend
(source : string,
recipient : string,
amount : number)
: Promise< {ok : true,
tx : string}
| {ok : false,
reason : string}
>
{
console.log('popup mk_spend', {source: source, recipient: recipient, amount: amount});
let nonce: number = active_account_next_nonce;
let req_obj = {recipient_id : recipient,
amount : amount,
fee : MIN_FEE,
ttl : 0,
sender_id : source,
nonce : nonce,
payload : ''};
console.log('popup mk_spend req_obj', req_obj);
let req_body = JSON.stringify(req_obj, undefined, 4);
console.log('popup mk_spend req_body', req_body);
let endpoint_init_url = 'https://demonet.qpq.swiss/v2';
let this_endpoint = endpoint_init_url + '/debug/transactions/spend';
// fetch: https://developer.mozilla.org/en-US/docs/Web/API/fetch
let response = await fetch(this_endpoint, {method: 'POST', body: req_body, headers: [['Content-Type', 'application/json']]});
let return_data = await response.json();
console.log('popup mk_spend return data', return_data);
// 200 = ok
// 400 = pubkey malformed
// 404 = account dne
switch (response.status) {
case 200:
// get the nonce
// @ts-ignore talking to foreign api
return {ok: true, tx: return_data.tx};
// wtf
default:
// @ts-ignore talking to foreign api
return {ok: false, reason: return_data.reason};
}
}
async function
get_nonce
(source: string)
: Promise<number>
{
console.log('popup get_nonce', source);
let endpoint_init_url = 'https://demonet.qpq.swiss/v2';
let this_endpoint = endpoint_init_url + '/accounts/' + source;
// fetch: https://developer.mozilla.org/en-US/docs/Web/API/fetch // fetch: https://developer.mozilla.org/en-US/docs/Web/API/fetch
let response = await fetch(this_endpoint); let response = await fetch(this_endpoint);
// 200 = ok // 200 = ok
@@ -261,12 +517,48 @@ pi_balance
switch (response.status) { switch (response.status) {
case 200: case 200:
// unstringify the body // unstringify the body
let return_data = response.json(); let return_data = await response.json();
console.log('popup get_nonce return data', return_data);
// get the nonce
// @ts-ignore talking to foreign api
return return_data.nonce;
// wtf
default:
return 0;
}
}
/**
* get account balance of ak_... str
*/
async function
pi_balance
(akstr : string)
: Promise< {ok : true,
balance : string,
nonce : number}
| {ok : false,
reason : string}
>
{
let endpoint_init_url = 'https://demonet.qpq.swiss/v2';
let this_endpoint = endpoint_init_url + '/accounts/' + akstr;
// fetch: https://developer.mozilla.org/en-US/docs/Web/API/fetch
let response = await fetch(this_endpoint);
// 200 = ok
// 400 = pubkey malformed
// 404 = account dne
switch (response.status) {
case 200:
// unstringify the body
let return_data = await response.json();
console.log('return data', return_data);
// get the balance // get the balance
// @ts-ignore talking to foreign api // @ts-ignore talking to foreign api
let balance = return_data.balance; let balance = return_data.balance.toString();
return {ok : true, return {ok : true,
balance : balance}; balance : balance,
nonce : return_data.nonce};
// pubkey malformed // pubkey malformed
case 400: case 400:
return {ok : false, return {ok : false,
@@ -274,10 +566,11 @@ pi_balance
// account dne // account dne
case 404: case 404:
return {ok : false, return {ok : false,
reason : 'Account DNE'}; reason : 'Account does not exist yet'};
// wtf // wtf
default: default:
return {ok : false, return {ok : false,
reason : 'Unexpected response from node'}; reason : 'Unexpected response from node'};
} }
} }