-
Notifications
You must be signed in to change notification settings - Fork 7
manual maker selection #93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1453,7 +1453,7 @@ function registerCoinswapHandlers() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Start coinswap | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ipcMain.handle( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'coinswap:start', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async (event, { amount, makerCount, outpoints, password }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async (event, { amount, makerCount, outpoints, password, selectedMakerAddresses }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!api1State.takerInstance) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { success: false, error: 'Taker not initialized' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1464,6 +1464,14 @@ function registerCoinswapHandlers() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { success: false, error: 'Invalid amount' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selectedMakerAddresses != null && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (!Array.isArray(selectedMakerAddresses) || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selectedMakerAddresses.some((a) => typeof a !== 'string' || !a.trim())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { success: false, error: 'Invalid selectedMakerAddresses: must be an array of non-empty strings' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1467
to
+1474
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial | 💤 Low value Validation looks good; consider also enforcing length and uniqueness. The added type/shape validation correctly addresses the prior concern. As an optional hardening, the handler does not currently enforce that ♻️ Optional tightening if (
selectedMakerAddresses != null &&
(!Array.isArray(selectedMakerAddresses) ||
selectedMakerAddresses.some((a) => typeof a !== 'string' || !a.trim()))
) {
return { success: false, error: 'Invalid selectedMakerAddresses: must be an array of non-empty strings' };
}
+
+ if (Array.isArray(selectedMakerAddresses) && selectedMakerAddresses.length > 0) {
+ const unique = new Set(selectedMakerAddresses.map((a) => a.trim()));
+ if (unique.size !== selectedMakerAddresses.length) {
+ return { success: false, error: 'selectedMakerAddresses contains duplicates' };
+ }
+ if (unique.size < makerCount) {
+ return {
+ success: false,
+ error: `Need ${makerCount} makers, only ${unique.size} selected`,
+ };
+ }
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const protocol = api1State.protocolVersion || 'v1'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const protocolName = protocol === 'v2' ? 'Taproot' : 'P2WSH'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const swapId = `swap_${Date.now()}_${Math.random().toString(36).substring(7)}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1571,7 +1579,7 @@ function registerCoinswapHandlers() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const worker = new Worker(path.join(__dirname, 'coinswap-worker.js'), { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workerData: { amount, makerCount, outpoints, config }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workerData: { amount, makerCount, outpoints, selectedMakerAddresses, config }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| api1State.activeSwaps.set(swapId, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,20 +38,14 @@ export function Market(container) { | |
| } | ||
| } | ||
|
|
||
| function formatTorEndpoint(address, start = 6, end = 0) { | ||
| function formatTorEndpoint(address, start = 8, end = 6) { | ||
| if (!address || typeof address !== 'string') return 'unknown'; | ||
|
|
||
| const separatorIndex = address.lastIndexOf(':'); | ||
| if (separatorIndex === -1) return address; | ||
| const host = (separatorIndex !== -1 ? address.slice(0, separatorIndex) : address).replace(/\.onion$/i, ''); | ||
|
|
||
| const host = address.slice(0, separatorIndex).replace(/\.onion$/i, ''); | ||
| const port = address.slice(separatorIndex + 1); | ||
|
|
||
| if (host.length <= start + end + 3) { | ||
| return `${host}:${port}`; | ||
| } | ||
|
|
||
| return end > 0 ? `${host.slice(0, start)}..${host.slice(-end)}:${port}` : `${host.slice(0, start)}..:${port}`; | ||
| if (host.length <= start + end + 3) return host; | ||
| return `${host.slice(0, start)}...${host.slice(-end)}`; | ||
| } | ||
|
|
||
| // Check sync state every second | ||
|
|
@@ -92,12 +86,11 @@ export function Market(container) { | |
| const addr = item.address; | ||
| let fullAddress; | ||
| if (typeof addr === 'string') { | ||
| fullAddress = addr.includes(':') ? addr : `${addr}:6102`; | ||
| fullAddress = addr; | ||
| } else { | ||
| const addressObj = addr || {}; | ||
| const onionAddr = addressObj.onion_addr || ''; | ||
| const port = addressObj.port || '6102'; | ||
| fullAddress = `${onionAddr}:${port}`; | ||
| const host = addr?.onion_addr || ''; | ||
| const portSuffix = addr?.port ? `:${addr.port}` : ''; | ||
| fullAddress = host || portSuffix ? `${host}${portSuffix}` : ''; | ||
| } | ||
|
Comment on lines
88
to
94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Edge case: port-only object can still produce a leading-colon string. The new logic correctly avoids the bare Suggest gating on 🛡️ Proposed guard if (typeof addr === 'string') {
fullAddress = addr;
} else {
- const host = addr?.onion_addr || '';
- const portSuffix = addr?.port ? `:${addr.port}` : '';
- fullAddress = host || portSuffix ? `${host}${portSuffix}` : '';
+ const host = addr?.onion_addr || '';
+ const portSuffix = host && addr?.port ? `:${addr.port}` : '';
+ fullAddress = host ? `${host}${portSuffix}` : '';
}🤖 Prompt for AI Agents |
||
|
|
||
| // Handle null offers (unresponsive makers) | ||
|
|
@@ -770,7 +763,7 @@ export function Market(container) { | |
| .map( | ||
| (maker) => { | ||
| return ` | ||
| <div class="grid grid-cols-7 gap-4 p-4 hover:bg-[#242d3d] transition-colors"> | ||
| <div class="grid gap-4 p-4 hover:bg-[#242d3d] transition-colors" style="grid-template-columns: 2fr 1fr 1fr 1fr 1fr 1fr 1fr"> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial | 💤 Low value Inline grid-template-columns duplicated between header and rows. The same 7-column template string is repeated in the header (line 867) and on every row render (line 766). Extracting it into a single constant avoids drift if the layout is adjusted later (e.g., adding a column). Also applies to: 867-867 🤖 Prompt for AI Agents |
||
|
|
||
| <div class="text-gray-300 font-mono text-sm truncate" title="${maker.address}">${formatTorEndpoint(maker.address)}</div> | ||
| <div class="text-green-400">${maker.baseFee}</div> | ||
|
|
@@ -871,7 +864,7 @@ export function Market(container) { | |
|
|
||
|
|
||
|
|
||
| <div class="grid grid-cols-7 gap-4 bg-[#FF6B35] p-4 text-xs"> | ||
| <div class="grid gap-4 bg-[#FF6B35] p-4 text-xs" style="grid-template-columns: 2fr 1fr 1fr 1fr 1fr 1fr 1fr"> | ||
| <div class="font-semibold">Tor Address</div> | ||
| <div class="font-semibold">Base Fee</div> | ||
| <div class="font-semibold">% Fee Rate</div> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -140,7 +140,7 @@ export function FirstTimeSetupModal(container, onComplete) { | |
|
|
||
| <div id="rpc-test-result" class="hidden"></div> | ||
|
|
||
| <div class="bg-yellow-500/10 border border-yellow-500/30 rounded-lg p-4"> | ||
| <div id="node-setup-info" class="hidden bg-yellow-500/10 border border-yellow-500/30 rounded-lg p-4"> | ||
| <div class="flex items-start gap-3 text-sm text-yellow-400"> | ||
| ${iconInfo} | ||
| <p> | ||
|
|
@@ -485,7 +485,7 @@ export function FirstTimeSetupModal(container, onComplete) { | |
|
|
||
| <div id="tor-test-result" class="hidden"></div> | ||
|
|
||
| <div class="bg-blue-500/10 border border-blue-500/30 rounded-lg p-4"> | ||
| <div id="tor-setup-info" class="hidden bg-blue-500/10 border border-blue-500/30 rounded-lg p-4"> | ||
| <div class="flex items-start gap-3 text-xs text-blue-400"> | ||
| ${iconInfo} | ||
| <p> | ||
|
|
@@ -986,6 +986,9 @@ export function FirstTimeSetupModal(container, onComplete) { | |
| ]; | ||
|
|
||
| renderConnectionResults(resultDiv, results); | ||
| const nodeFailed = results.some((r) => !r.ok); | ||
| const infoDiv = modal.querySelector('#node-setup-info'); | ||
| if (infoDiv) infoDiv.classList.toggle('hidden', !nodeFailed); | ||
| } catch (error) { | ||
| console.error('RPC test failed:', error); | ||
|
|
||
|
|
@@ -1000,6 +1003,8 @@ export function FirstTimeSetupModal(container, onComplete) { | |
| : error.message, | ||
| }, | ||
| ]); | ||
| const infoDiv = modal.querySelector('#node-setup-info'); | ||
| if (infoDiv) infoDiv.classList.remove('hidden'); | ||
| } | ||
|
|
||
| btn.textContent = originalText; | ||
|
|
@@ -1090,6 +1095,7 @@ export function FirstTimeSetupModal(container, onComplete) { | |
| window.api.testTcpPort({ host: '127.0.0.1', port: controlPort }), | ||
| ]); | ||
|
|
||
| const torFailed = !socksResult?.success || !controlResult?.success; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial | 💤 Low value
In the RPC path ♻️ Suggested alignment- const torFailed = !socksResult?.success || !controlResult?.success;
renderConnectionResults(resultDiv, [
{
label: 'SOCKS Port',
ok: Boolean(socksResult?.success),
message: socksResult?.success
? `Port ${socksPort} reachable`
: socksResult?.error,
},
{
label: 'Control Port',
ok: Boolean(controlResult?.success),
message: controlResult?.success
? `Port ${controlPort} reachable`
: controlResult?.error,
},
]);
+ const torFailed = !socksResult?.success || !controlResult?.success;
const infoDiv = modal.querySelector('#tor-setup-info');
if (infoDiv) infoDiv.classList.toggle('hidden', !torFailed);🤖 Prompt for AI Agents |
||
| renderConnectionResults(resultDiv, [ | ||
| { | ||
| label: 'SOCKS Port', | ||
|
|
@@ -1106,6 +1112,8 @@ export function FirstTimeSetupModal(container, onComplete) { | |
| : controlResult?.error, | ||
| }, | ||
| ]); | ||
| const infoDiv = modal.querySelector('#tor-setup-info'); | ||
| if (infoDiv) infoDiv.classList.toggle('hidden', !torFailed); | ||
| } catch (error) { | ||
| console.error('Tor test failed:', error); | ||
|
|
||
|
|
@@ -1116,6 +1124,8 @@ export function FirstTimeSetupModal(container, onComplete) { | |
| message: error.message || String(error), | ||
| }, | ||
| ]); | ||
| const infoDiv = modal.querySelector('#tor-setup-info'); | ||
| if (infoDiv) infoDiv.classList.remove('hidden'); | ||
| } | ||
|
|
||
| btn.textContent = originalText; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.