Atompek Swap & CORs

When I'm trying to make swaps work... but I keep getting CORs errors.

Minimal fun.

So these gosh darn CORs's, lol.

Am I not calling for it correctly? It's been a few months of work to build this thing. I'm a bit of an ADD type of character, so I am all over the place but still trying to get shit done.

Help!!

I may end up having this fixed, but right now I'm at my wits' end. So slide some knowledge on me, folks.

// script.js - Handles the frontend logic for atomic swap UI (Keychain & Hivesigner DEX version)

// List of Hive Engine API endpoints (primary and backups)
const HIVE_ENGINE_APIS = [
    'https://api.hive-engine.com/rpc',
    'https://herpc.dtools.dev',
    'https://heapi.inleo.io',
    'https://api.primersion.com',
    'https://api.ausbit.dev',
    'https://api.tribaldex.com/rpc'
];

// Helper: Try all APIs in order until one succeeds
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) {}
    }
    return null;
}

async function fetchSwapHiveRate(token) {
    // Try buyBook (best ask)
    try {
        const data = await fetchWithBackups({
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                jsonrpc: '2.0',
                id: 1,
                method: 'find',
                params: {
                    contract: 'market',
                    table: 'buyBook',
                    query: { symbol: token, baseSymbol: 'SWAP.HIVE' },
                    limit: 1,
                    indexes: [{ index: 'price', descending: true }]
                }
            })
        });
        if (data && data.result && data.result.length > 0 && data.result[0].price && !isNaN(data.result[0].price)) {
            return parseFloat(data.result[0].price);
        }
    } catch (e) {}
    // Try metrics as fallback
    try {
        const data = await fetchWithBackups({
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                jsonrpc: '2.0',
                id: 1,
                method: 'findOne',
                params: {
                    contract: 'market',
                    table: 'metrics',
                    query: { symbol: token }
                }
            })
        });
        if (data && data.result && data.result.lastPrice && !isNaN(data.result.lastPrice)) {
            return parseFloat(data.result.lastPrice);
        }
    } catch (e) {}
    return null;
}

// --- UI Rate Display Logic (modified) ---
async function updateRateDisplay() {
    const token = document.getElementById('hiveToken').value;
    const tokenAmount = parseFloat(document.getElementById('hiveAmount').value);
    const rateDisplay = document.getElementById('rateDisplay');
    if (tokenAmount > 0) {
        const swapHiveRate = await fetchSwapHiveRate(token);
        if (swapHiveRate) {
            const pekAmount = tokenAmount * swapHiveRate;
            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.';
        }
    } else {
        rateDisplay.textContent = '';
    }
}
document.getElementById('hiveAmount').addEventListener('input', updateRateDisplay);
document.getElementById('hiveToken').addEventListener('change', updateRateDisplay);
window.addEventListener('DOMContentLoaded', updateRateDisplay);

// --- Helper: Build Hive Engine custom_json for marketSell/marketBuy ---
function buildMarketSellJson(account, symbol, quantity) {
    return {
        contractName: "market",
        contractAction: "marketSell",
        contractPayload: {
            symbol: symbol,
            quantity: String(quantity)
        }
    };
}
function buildMarketBuyJson(account, symbol, quantity) {
    return {
        contractName: "market",
        contractAction: "marketBuy",
        contractPayload: {
            symbol: symbol,
            quantity: String(quantity)
        }
    };
}

// --- Helper: Hivesigner custom_json link ---
function buildHivesignerCustomJsonLink(account, json, authority = 'Active') {
    const op = [
        'custom_json',
        {
            required_auths: [account],
            required_posting_auths: [],
            id: 'ssc-mainnet-hive',
            json: JSON.stringify(json)
        }
    ];
    const ops = encodeURIComponent(JSON.stringify([op]));
    return `https://hivesigner.com/sign/tx?operations=${ops}&authority=${authority}`;
}

// --- Combined Swap: Sell Token for SWAP.HIVE, then Buy PEK ---
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');
    swapResult.innerHTML = '';
    if (!account || !symbol || !quantity || quantity <= 0) {
        swapResult.innerHTML = "Please fill in all fields.";
        return;
    }
    // Step 1: Sell selected token for SWAP.HIVE
    const sellJson = buildMarketSellJson(account, symbol, quantity);
    if (useKeychain) {
        if (!window.hive_keychain) {
            swapResult.innerHTML = "Hive Keychain extension not detected.";
            return;
        }
        // Use a non-async callback for Keychain (Keychain expects a regular function, not async)
        window.hive_keychain.requestCustomJson(
            account,
            'ssc-mainnet-hive',
            'Active',
            JSON.stringify(sellJson),
            `Sell ${quantity} ${symbol} for SWAP.HIVE`,
            function(response) {
                if (response.success) {
                    swapResult.innerHTML = "Sell order broadcasted! Waiting for your SWAP.HIVE payout...";
                    // Poll for payout up to 30s, every 2s
                    let payout = 0;
                    let pollCount = 0;
                    const pollPayout = async function() {
                        payout = await getLastSwapHivePayoutFromLogs(account, symbol);
                        if (payout > 0.000001) {
                            performBuyPEK(account, payout, true);
                        } else if (++pollCount < 15) {
                            setTimeout(pollPayout, 2000);
                        } else {
                            swapResult.innerHTML = "No SWAP.HIVE payout detected from your sale after 30 seconds. Please check your wallet and try again.";
                        }
                    };
                    setTimeout(pollPayout, 2000);
                } else {
                    swapResult.innerHTML = "Keychain error: " + (response.message || "Unknown error");
                }
            }
        );
    } else {
        const url = buildHivesignerCustomJsonLink(account, sellJson, 'Active');
        window.open(url, '_blank');
        swapResult.innerHTML = "Sell order link opened in Hivesigner. Waiting for your SWAP.HIVE payout...";
        // Poll for payout up to 30s, every 2s
        let pollCount = 0;
        let payout = 0;
        const pollPayout = async function() {
            payout = await getLastSwapHivePayoutFromLogs(account, symbol);
            if (payout > 0.000001) {
                performBuyPEK(account, payout, false);
            } else if (++pollCount < 15) {
                setTimeout(pollPayout, 2000);
            } else {
                swapResult.innerHTML = "No SWAP.HIVE payout detected from your sale after 30 seconds. Please check your wallet and try again.";
            }
        };
        setTimeout(pollPayout, 2000);
    }
}

// Fetch the user's SWAP.HIVE balance from Hive Engine
async function getSwapHiveBalance(account) {
    try {
        const res = await fetch('https://api.hive-engine.com/rpc', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                jsonrpc: '2.0',
                id: 1,
                method: 'findOne',
                params: {
                    contract: 'tokens',
                    table: 'balances',
                    query: { account: account, symbol: 'SWAP.HIVE' }
                }
            })
        });
        const data = await res.json();
        if (data && data.result && data.result.balance) {
            return parseFloat(data.result.balance);
        }
    } catch (e) {}
    return 0;
}

// Fetch the most recent SWAP.HIVE payout from a marketSell for the selected token
async function getLastSwapHivePayout(account, symbol) {
    try {
        const res = await fetch('https://api.hive-engine.com/rpc', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                jsonrpc: '2.0',
                id: 1,
                method: 'find',
                params: {
                    contract: 'market',
                    table: 'trades',
                    query: { account: account, symbol: symbol, market: 'SWAP.HIVE' },
                    limit: 10,
                    indexes: [{ index: 'timestamp', descending: true }]
                }
            })
        });
        const data = await res.json();
        if (data && data.result && data.result.length > 0) {
            // Find the most recent trade where the user was the seller and payoutSymbol is SWAP.HIVE
            for (const trade of data.result) {
                if (trade.account === account && trade.symbol === symbol && trade.payoutSymbol === 'SWAP.HIVE') {
                    return parseFloat(trade.payoutQuantity);
                }
            }
        }
    } catch (e) {}
    return 0;
}

// Fetch the most recent SWAP.HIVE payout from a marketSell for the selected token using logs/events
async function getLastSwapHivePayoutFromLogs(account, symbol) {
    try {
        // Query the last 10 blocks for marketSell actions by the user
        const res = await fetch('https://api.hive-engine.com/rpc', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                jsonrpc: '2.0',
                id: 1,
                method: 'find',
                params: {
                    contract: 'blockLog',
                    table: 'blocks',
                    query: {},
                    limit: 10,
                    indexes: [{ index: 'blockNumber', descending: true }]
                }
            })
        });
        const data = await res.json();
        if (data && data.result && data.result.length > 0) {
            for (const block of data.result) {
                if (block.transactions) {
                    for (const tx of block.transactions) {
                        if (tx.sender === account && tx.contract === 'market' && tx.action === 'marketSell' && tx.payload && tx.payload.symbol === symbol) {
                            // Look for a transferFromContract event for SWAP.HIVE to the user
                            if (tx.logs && tx.logs.events) {
                                for (let i = 0; i < tx.logs.events.length; i++) {
                                    const event = tx.logs.events[i];
                                    if (event.contract === 'tokens' && event.event === 'transferFromContract' && event.data && event.data.to === account && event.data.symbol === 'SWAP.HIVE') {
                                        return parseFloat(event.data.quantity);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } catch (e) {}
    return 0;
}

// --- Combined Swap: Sell Token for SWAP.HIVE, then Buy PEK ---
async function performBuyPEK(account, swapHiveAmount, useKeychain) {
    const swapResult = document.getElementById('swapResult');
    // Subtract Hive Engine multiTransaction fee (0.001 SWAP.HIVE)
    const MULTI_TX_FEE = 0.001;
    let buyAmount = swapHiveAmount - MULTI_TX_FEE;
    if (buyAmount <= 0) {
        swapResult.innerHTML = "Insufficient SWAP.HIVE amount after fee deduction.";
        return;
    }
    const buyJson = buildMarketBuyJson(account, 'PEK', buyAmount);
    if (useKeychain) {
        if (!window.hive_keychain) {
            swapResult.innerHTML = "Hive Keychain extension not detected.";
            return;
        }
        window.hive_keychain.requestCustomJson(
            account,
            'ssc-mainnet-hive',
            'Active',
            JSON.stringify(buyJson),
            `Buy PEK with ${buyAmount} SWAP.HIVE`,
            function(response) {
                if (response.success) {
                    swapResult.innerHTML = "Buy order broadcasted!";
                } else {
                    swapResult.innerHTML = "Keychain error: " + (response.message || "Unknown error");
                }
            }
        );
    } else {
        const url = buildHivesignerCustomJsonLink(account, buyJson, 'Active');
        window.open(url, '_blank');
        swapResult.innerHTML = "Buy order link opened in Hivesigner.";
    }
}


0
0
0.000
2 comments
avatar

try running it locally in a simple http server like this:
go into the folder with the code and run python3 -m http.server 9000 -d . and see if it works, you may not be able to make the cross api calls from your host, it might not be the code itself.

0
0
0.000
avatar

It was working but it wasn't swapping the correct amounts I played around with it and now it's giving me this.

Ill be adding logging and debugging in the window of the browser tomorrow.

0
0
0.000