From 422fccfa88c22a31802a6e991c03b505152af012 Mon Sep 17 00:00:00 2001 From: Peter Harpending Date: Wed, 20 Mar 2024 02:41:34 -0600 Subject: [PATCH] [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. --- jrx/pages/popup.html | 24 +++++ jrx/src/popup.ts | 235 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 242 insertions(+), 17 deletions(-) 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,