IMG-LOGO

PeakeCoin AtomPEK Swap - JavaScript Updates

paulmoon410 - 2025-06-08 02:53:21


On the route to greatness you often use a lot of swear words. I had a lot of issues trying to get this whole Atomic Swap function. I have it working on the sell of each token, but the buys don't seem to be working.


I have created a he_cors_proxy.py to the CORS work around and have launched it on a free service. I'll write that up in the next few days.


Have I eliminated the CORS problems, yes. Does it work right now? Not exactly sure.




script.js - Main entry point. Wires up UI, handles form input, and triggers the swap logic.


```

import { fetchWithBackups, getHiveBlockNumberForTxId } from './api.js';

import { getSwapHivePayoutForTx, performSwap } from './swapLogic.js';

import { updateRateDisplay, setSwapResult } from './ui.js';

import { logDebug } from './utils.js';


logDebug('App loaded.');


async function handleRateDisplay() {

const token = document.getElementById('hiveToken').value;

const tokenAmount = parseFloat(document.getElementById('hiveAmount').value);

if (tokenAmount > 0) {

const swapHiveRate = await fetchSwapHiveRate(token);

updateRateDisplay(swapHiveRate, tokenAmount, token);

} else {

updateRateDisplay(null, 0, token);

}

}

document.getElementById('hiveAmount').addEventListener('input', handleRateDisplay);

document.getElementById('hiveToken').addEventListener('change', handleRateDisplay);

window.addEventListener('DOMContentLoaded', handleRateDisplay);


document.getElementById('swapKeychain').addEventListener('click', function(e) {

e.preventDefault();

logDebug('swapKeychain button clicked');

performSwap(true);

});

document.getElementById('swapHivesigner').addEventListener('click', function(e) {

e.preventDefault();

logDebug('swapHivesigner button clicked');

performSwap(false);

});

```


swapLogic.js - Orchestrates the swap. Validates input, kicks off sell, polls for payout, and triggers buy PEK.


```


import { fetchWithBackups, getHiveBlockNumberForTxId } from './api.js';

import { logDebug } from './utils.js';

import { performKeychainSell, performKeychainBuy } from './keychain.js';


export async function performSwap(useKeychain) {

const account = document.getElementById('hiveSender').value.trim();

const symbol = document.getElementById('hiveToken').value;

const quantity = parseFloat(document.getElementById('hiveAmount').value);

const swapResult = document.getElementById('swapResult');

logDebug(Swap requested: account=${account}, symbol=${symbol}, quantity=${quantity}, useKeychain=${useKeychain});

swapResult.innerHTML = '';

if (!account || !symbol || !quantity || quantity <= 0) {

swapResult.innerHTML = "Please fill in all fields.";

logDebug('Swap aborted: missing fields.');

return;

}

if (symbol === 'SCALA') {

logDebug('Scala swap selected.');

swapResult.innerHTML = 'Scala swap not implemented in this module.';

return;

}

if (useKeychain) {

performKeychainSell(account, symbol, quantity, swapResult, getSwapHivePayoutForTx, getLastSwapHivePayout, performBuyPEK);

} else {

logDebug('Opening Hivesigner for marketSell.');

swapResult.innerHTML = "Hivesigner flow not implemented in this module.";

}

}


```


keychain.js

Handles signing and broadcasting Hive Keychain transactions, both for sell and buy. Polls for payout and triggers buy automatically.


```


import { logDebug } from './utils.js';


export function performKeychainSell(account, symbol, quantity, swapResult, getSwapHivePayoutForTx, getLastSwapHivePayout, performBuyPEK) {

if (!window.hive_keychain) {

swapResult.innerHTML = "Hive Keychain extension not detected.";

logDebug('Hive Keychain not detected.');

return;

}

const sellJson = {

contractName: "market",

contractAction: "marketSell",

contractPayload: {

symbol: symbol,

quantity: String(quantity)

}

};

logDebug('Requesting Keychain signature for marketSell...');

window.hive_keychain.requestCustomJson(

account,

'ssc-mainnet-hive',

'Active',

JSON.stringify(sellJson),

Sell ${quantity} ${symbol} for SWAP.HIVE,

function(response) {

logDebug('Keychain response: ' + JSON.stringify(response));

if (response.success) {

swapResult.innerHTML = "Sell order broadcasted! Waiting for your SWAP.HIVE payout...";

let payout = 0;

let pollCount = 0;

let lastPayout = 0;

const txId = response.result && response.result.tx_id ? response.result.tx_id : null;

const pollPayout = async function() {

payout = txId ? await getSwapHivePayoutForTx(account, symbol, txId) : 0;

if (!payout || payout <= 0) {

payout = await getLastSwapHivePayout(account, symbol);

}

logDebug(Polling payout (txId=${txId}): ${payout});

if (payout > lastPayout + 0.0000001) {

lastPayout = payout;

swapResult.innerHTML += '
SWAP.HIVE payout detected! Waiting 10 seconds before buying PEK...';

logDebug('SWAP.HIVE payout detected. Waiting 10 seconds before auto-buying PEK.');

setTimeout(function() {

logDebug('Auto-buying PEK after 10s delay.');

performBuyPEK(account, payout, true);

}, 10000);

} else if (++pollCount < 30) {

setTimeout(pollPayout, 2000);

} else {

swapResult.innerHTML = "No new SWAP.HIVE payout detected from your sale after 60 seconds. Please check your wallet and try again.";

logDebug('Payout polling timed out.');

}

};

setTimeout(pollPayout, 2000);

} else {

swapResult.innerHTML = "Keychain error: " + (response.message || "Unknown error");

logDebug('Keychain error: ' + (response.message || 'Unknown error'));

}

}

);

}


export function performKeychainBuy(account, swapHiveAmount, swapResult) {

const MULTI_TX_FEE = 0.001;

let buyAmount = swapHiveAmount - MULTI_TX_FEE;

logDebug(Preparing to buy PEK: swapHiveAmount=${swapHiveAmount}, buyAmount=${buyAmount}, useKeychain=true);

if (buyAmount <= 0) {

swapResult.innerHTML = "Insufficient SWAP.HIVE amount after fee deduction.";

logDebug('Buy aborted: insufficient SWAP.HIVE after fee.');

return;

}

const buyJson = {

contractName: "market",

contractAction: "marketBuy",

contractPayload: {

symbol: 'PEK',

quantity: String(buyAmount)

}

};

logDebug('Requesting Keychain signature for marketBuy...');

window.hive_keychain.requestCustomJson(

account,

'ssc-mainnet-hive',

'Active',

JSON.stringify(buyJson),

Buy PEK with ${buyAmount} SWAP.HIVE,

function(response) {

logDebug('Keychain response (buy): ' + JSON.stringify(response));

if (response.success) {

swapResult.innerHTML = "Buy order broadcasted!";

} else {

swapResult.innerHTML = "Keychain error: " + (response.message || "Unknown error");

logDebug('Keychain error (buy): ' + (response.message || 'Unknown error'));

}

}

);

}

```

api.js - Handles network logic for Hive Engine and Hive, with endpoint failover.


```

export const HIVE_ENGINE_APIS = [

'https://peake-swap.onrender.com/he-proxy'

];


export const CORS_PROXY = 'https://corsproxy.io/?';


export async function fetchWithBackups(options) {

for (let i = 0; i < HIVE_ENGINE_APIS.length; i++) {

try {

const res = await fetch(HIVE_ENGINE_APIS[i], options);

if (res.ok) return await res.json();

} catch (e) {}

}

for (let i = 0; i < HIVE_ENGINE_APIS.length; i++) {

try {

const res = await fetch(CORS_PROXY + HIVE_ENGINE_APIS[i], options);

if (res.ok) return await res.json();

} catch (e) {}

}

return null;

}


**ui.js**- Updates the DOM for rates and swap results.

import { logDebug } from './utils.js';


export function updateRateDisplay(rate, tokenAmount, token) {

const rateDisplay = document.getElementById('rateDisplay');

if (rate && tokenAmount > 0) {

const pekAmount = tokenAmount * rate;

rateDisplay.innerHTML = Estimated: <b>${pekAmount.toFixed(6)} PEK</b> for <b>${tokenAmount} ${token}</b><br><span style='font-size:0.95em;color:#fff;'>Final swap rate is determined by the market at the time of each transaction.</span>;

} else {

rateDisplay.textContent = 'Unable to fetch live SWAP.HIVE rate.';

}

}


export function setSwapResult(msg) {

document.getElementById('swapResult').innerHTML = msg;

}

```


utils.js - General helpers and debug logging.

```

js


export function logDebug(msg) {

const el = document.getElementById('debugLogContent');

if (el) {

const now = new Date().toLocaleTimeString();

const entry = <span style="font-size:0.82em;line-height:1.5;display:block;margin-bottom:2px;">[${now}] ${msg}</span>;

el.innerHTML += entry;

el.scrollTop = el.scrollHeight;

}

}