Linked positions (Qualified Start): extra wallets on one account, credits pooled, buy-from picker

- accounts/db: positions table + JSON store (add/list/owner/remove; main-wallet and cross-account guards)
- auth verify: asPosition links a second wallet without touching the session; position wallets can't mint a session
- /api/my/positions (chain-refreshed member ids, buyer counts, credits) + remove
- credits pooled across main + positions on /api/me, dashboard, campaigns; campaign charged to the best-funded position
- My line: own positions listed on level 1 as 'You · position N'
- Buy pane: Qualified Start card + Add a position flow + Buy-from picker with connected-wallet guard
- Wallet pane: Your positions card; chatbot answer updated

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-09 17:18:47 -05:00
parent b86dbfd9e9
commit 046464b83e
9 changed files with 327 additions and 14 deletions
+25
View File
@@ -324,8 +324,27 @@
to this account instantly, and every payout in your sponsor line lands the moment you confirm.</p>
<p class="small" style="border:1px solid var(--line-strong);border-radius:10px;padding:10px 12px;margin:0 0 14px">
<b>Using Trust Wallet?</b> It blocks purchases that spend most of the POL in the wallet (a "drain your wallet" warning). Start with a smaller package, keep a little extra POL, or connect MetaMask, Phantom or SafePal instead. Extra POL always stays yours.</p>
<div id="buyFromWrap" class="small" hidden style="border:1px solid var(--line-strong);border-radius:10px;padding:10px 12px;margin:0 0 14px;display:flex;gap:10px;align-items:center;flex-wrap:wrap">
<b>Buy from</b>
<select id="buyFrom" class="input" style="max-width:340px"></select>
<span class="muted" id="buyFromHint">Your wallet app must be on this account when you confirm.</span>
</div>
<div class="tiles" id="boTiles"><div class="tile"><span class="muted small">Loading live prices…</span></div></div>
</div>
<div class="card" id="qsCard">
<h3>Qualified Start: your own positions</h3>
<p class="muted small">Qualification is earned by buyers you refer, and it is never for sale. But nothing stops you from being your own first buyers, openly. Link a second wallet of your own as a <b>position</b> under your account. When it buys a $20 or larger package, the contract counts it as a qualifying buyer, half the purchase comes straight back to your main wallet, and the credits it mints pool with yours. Two positions open level 2 the same day. Five open level 3.</p>
<ol class="small" style="margin:0 0 12px 18px;padding:0;line-height:1.6">
<li>Link your main wallet and switch on payouts (Wallet tab) so positions can register under you.</li>
<li>In your wallet app, create or switch to a <b>different account</b> (MetaMask: account menu, Add account. Trust or SafePal: switch wallet). Put enough POL in it for a $20 package plus gas.</li>
<li>Click <b>Add a position</b>, pick that account in the picker, and sign once.</li>
<li>Choose it under <b>Buy from</b> above and buy a $20 or larger package.</li>
</ol>
<p><button class="btn" id="qsAddBtn" type="button">Add a position</button>
<span class="small muted" id="qsHint"></span></p>
<div id="qsList" class="small"></div>
<p class="muted small" style="margin:12px 0 0">Your own money, your own wallets, a faster start. It is not an income promise: qualification only pays on future purchases in your line, and every purchase here is a real ad package you can spend.</p>
</div>
</div>
<div class="pane" id="pane-campaigns" hidden>
@@ -718,6 +737,12 @@
<p><button class="btn sec small" id="wcDisconnect" type="button">Disconnect wallet</button>
<span class="small muted" id="wcDisconnectInfo"></span></p>
</div>
<div class="card" id="posCard" hidden>
<h3>Your positions</h3>
<p class="muted small">Extra wallets you own, registered under your main member. Their credits pool with yours and each one that buys $20 or more counts toward your qualification.</p>
<div id="posList" class="small"></div>
<p style="margin:10px 0 0"><a class="btn sec small" href="#buy">Add or buy from a position</a></p>
</div>
<div class="grid c2">
<div class="card"><h3>Your account</h3>
<p id="posLine" class="muted small">…</p></div>