diff --git a/jrx/pages/popup.html b/jrx/pages/popup.html index a96eedc..d32b246 100644 --- a/jrx/pages/popup.html +++ b/jrx/pages/popup.html @@ -141,6 +141,30 @@ + +
+ + + + + +
+ SEND SOMEONE MONEY +
+ +
+ + +
+ + +
+ +
+ +

+
+

diff --git a/jrx/src/popup.ts b/jrx/src/popup.ts
index caf54e8..082f8dd 100644
--- a/jrx/src/popup.ts
+++ b/jrx/src/popup.ts
@@ -6,6 +6,10 @@ import * as b_lib from './b_lib.js';
 
 p_main();
 
+let EXPLORER_URL = 'https://explorer.qpq.swiss';
+
+let active_account_next_nonce = 0;
+
 /**
  * runs whenever the popup opens
  *
@@ -33,6 +37,8 @@ p_main
     console.log('popup main');
     await pi_repop();
 
+    let pdata = await b_lib.p_get_data();
+
 
     // add unique name for default
     let unique_name: string = await b_lib.p_get_unique_name();
@@ -70,6 +76,73 @@ p_main
     document
         .getElementById('faert-btn')!
         .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,
+    //        netid_cur   : string,
+    //        netids_alt  : Array};
+    // type p_rich_pubkey
+    //     = {akstr  : string,
+    //        active : boolean,
+    //        name   : string};
+    for (let rkp of pdata.rich_pubkeys) {
+        if (rkp.active)
+            return rkp.akstr;
+    }
+
+    return '';
 }
 
 
@@ -216,8 +289,17 @@ pi_repop
             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
@@ -226,8 +308,12 @@ pi_repop
                         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
@@ -313,20 +399,134 @@ pi_repop
 }
 
 
-//async function
-//mk_spend
-//    (source    : string,
-//     recipient : string,
-//     amount    : number)
-//{
-//    let nonce: number = await get_nonce(source);
-//}
-//
-//async function
-//get_nonce
-//    (source: string)
-//{
-//}
+async function
+do_spend
+    (source    : string,
+     recipient : string,
+     amount    : number)
+    : Promise< {ok      : true,
+                tx_hash : string}
+             | {ok      : false,
+                reason  : string}
+             >
+{
+    console.log('popup do_spend', {source: source, recipient: recipient, amount: amount});
+    let maybe_spendtx = await mk_spend(source, recipient, amount);
+    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
+{
+    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
+    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('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
@@ -335,14 +535,14 @@ async function
 pi_balance
     (akstr : string)
     : Promise< {ok      : true,
-                balance : string}
+                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;
-    let input_params              = {pubkey: akstr};
     // fetch: https://developer.mozilla.org/en-US/docs/Web/API/fetch
     let response = await fetch(this_endpoint);
     // 200 = ok
@@ -357,7 +557,8 @@ pi_balance
             // @ts-ignore talking to foreign api
             let balance = return_data.balance.toString();
             return {ok      : true,
-                    balance : balance};
+                    balance : balance,
+                    nonce   : return_data.nonce};
         // pubkey malformed
         case 400:
             return {ok     : false,