market: a dollar listing must not crash the Sell panel, and the gateway must not forget a fresh one
After a successful USD listing the panel tried to show the BCH-style offer hex, which dollar listings do not have, so the seller saw an error and a bare Cancel button. The panel now shows the contract address instead. The gateway pruned listings from its store whenever one electrum lookup did not show the covenant output. A listing a few seconds old can be invisible to one server while another already relayed it; deleting it then loses a real on-chain listing. Absence is now trusted only after 20 minutes; before that the listing is hidden from buyers but kept.
This commit is contained in:
parent
79a8a6fa16
commit
e94399a1d2
1 changed files with 15 additions and 5 deletions
|
|
@ -215,17 +215,26 @@ async function activeListings() {
|
|||
const stored = readMarket();
|
||||
if (!stored.length) { _marketCheck = { at: Date.now(), list: [] }; return []; }
|
||||
const idx = await getIndex();
|
||||
const keep = [];
|
||||
const keep = []; // shown to buyers
|
||||
const store = []; // kept on disk (a superset: a fresh usd listing may be
|
||||
// invisible to one electrum server for a while, and
|
||||
// deleting it then loses a real on-chain listing)
|
||||
const byLock = new Map();
|
||||
const USD_GRACE_MS = 20 * 60 * 1000;
|
||||
for (const l of stored) {
|
||||
const entry = idx.get(l.name);
|
||||
if (l.kind === "usd") {
|
||||
// Alive while the certificate still sits in the covenant.
|
||||
if (!entry || entry.category !== l.category) continue;
|
||||
// Alive while the certificate still sits in the covenant. Absence from
|
||||
// listunspent is only trusted once the listing is old enough for every
|
||||
// server to have seen its transaction; before that it is hidden, not
|
||||
// forgotten.
|
||||
const young = Date.now() - (Date.parse(l.created_at || "") || 0) < USD_GRACE_MS;
|
||||
if (!entry || entry.category !== l.category) { if (young) store.push(l); continue; }
|
||||
const clock = usdListingLockHex(l);
|
||||
if (!byLock.has(clock)) byLock.set(clock, await listUnspentForLock(clock).catch(() => null));
|
||||
const clist = byLock.get(clock);
|
||||
if (clist && !clist.some((u) => u.tx_hash === l.outpoint.txid && u.tx_pos === l.outpoint.vout)) continue; // bought or cancelled
|
||||
if (clist && !clist.some((u) => u.tx_hash === l.outpoint.txid && u.tx_pos === l.outpoint.vout)) { if (young) store.push(l); continue; } // bought or cancelled (or not relayed yet)
|
||||
store.push(l);
|
||||
keep.push({ ...l, records: entry.records ?? {} });
|
||||
continue;
|
||||
}
|
||||
|
|
@ -234,9 +243,10 @@ async function activeListings() {
|
|||
if (!byLock.has(lock)) byLock.set(lock, await listUnspentForLock(lock).catch(() => null));
|
||||
const list = byLock.get(lock);
|
||||
if (list && !list.some((u) => u.tx_hash === l.source_output.txid && u.tx_pos === l.source_output.vout)) continue; // spent
|
||||
store.push(l);
|
||||
keep.push({ ...l, records: entry.records ?? {} });
|
||||
}
|
||||
if (keep.length !== stored.length) writeMarket(keep);
|
||||
if (store.length !== stored.length) writeMarket(store);
|
||||
_marketCheck = { at: Date.now(), list: keep };
|
||||
return keep;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue