fix(invoice): auto-select worker's coinpay wallet when poster creates invoice#482
fix(invoice): auto-select worker's coinpay wallet when poster creates invoice#482russo2100 wants to merge 1 commit into
Conversation
… invoice Fixes profullstack#478. When the poster initiates an invoice on behalf of the worker, the frontend no longer forces the poster to select a CoinPay receiving wallet (which they wouldn't have access to). The backend API now automatically falls back to selecting the worker's CoinPay wallet matching the gig's payment coin.
Greptile SummaryThis PR removes the poster-side wallet selector requirement and shifts auto-selection of the worker's CoinPay wallet to the backend when the poster initiates an invoice. The frontend skips wallet loading/validation entirely for posters, and the API now picks the matching wallet from the worker's global wallet list when none is supplied.
Confidence Score: 2/5Not safe to merge — the frontend change introduces a compile-time error that blocks deployment. The
Important Files Changed
Sequence DiagramsequenceDiagram
participant Poster as Poster (Browser)
participant FE as InvoiceButton.tsx
participant API as POST /api/gigs/[id]/invoice
participant CoinPay as CoinPay API
Poster->>FE: "Opens invoice form (isWorker=false)"
Note over FE: Wallet selector hidden (isWorker guard)<br/>payment_currency & merchant_wallet_address = undefined
Poster->>FE: Submits invoice
FE->>API: "POST {items, amount, currency}"
API->>API: Validate schema (both fields optional)
API->>CoinPay: getConnectedCoinpayAccessToken(workerId)
CoinPay-->>API: worker access token
API->>CoinPay: getCoinpayGlobalWalletTokens(token)
CoinPay-->>API: workerWallets[]
Note over API: payment_currency missing, auto-select<br/>1. find wallet where currency === gigCoin<br/>2. fallback: workerWallets[0]
API->>API: findCoinpayGlobalWallet(selectedCurrency, selectedAddress)
API->>API: Insert gig_invoice record
API-->>FE: 201 invoice created
FE-->>Poster: Invoice displayed
Reviews (1): Last reviewed commit: "fix(invoice): auto-select worker's coinp..." | Re-trigger Greptile |
| @@ -906,14 +914,15 @@ function InvoiceForm({ | |||
| )} | |||
| </div> | |||
| )} | |||
| </div> | |||
| </div> | |||
| )} | |||
|
|
|||
| {error && <p className="text-sm text-destructive">{error}</p>} | |||
|
|
|||
| <div className="flex gap-2"> | |||
| <Button | |||
| onClick={onSubmit} | |||
| disabled={isCreating || total <= 0 || overCap || !hasWallets} | |||
| disabled={isCreating || total <= 0 || overCap || (isWorker && !hasWallets)} | |||
There was a problem hiding this comment.
isWorker is not a prop of InvoiceForm — compile error
isWorker is used at two points inside InvoiceForm (the wallet section conditional and the submit-button disabled expression), but it is never declared in the component's props interface and is never passed at either of the two call sites. TypeScript will emit Cannot find name 'isWorker' and refuse to compile, blocking deployment. Even if the build somehow succeeded, isWorker would be undefined (falsy), causing the wallet-selector section to be invisible to workers and the "no wallets" guard on the submit button to never fire.
isWorker needs to be added to InvoiceForm's props type and destructuring, then passed as a prop from every <InvoiceForm ... /> call site in InvoiceButton.
| if (!selectedCurrency || !selectedAddress) { | ||
| const gigCoin = preferredCoinToPaymentCurrency(gig.payment_coin || null); | ||
| const preferred = workerWallets.find((w) => w.currency === gigCoin) || workerWallets[0]; | ||
|
|
||
| if (preferred) { | ||
| selectedCurrency = preferred.currency; | ||
| selectedAddress = preferred.address; | ||
| } else { | ||
| return NextResponse.json( | ||
| { error: "Select a CoinPay receiving wallet before sending the invoice" }, | ||
| { status: 400 } | ||
| ); | ||
| } | ||
| } |
There was a problem hiding this comment.
Auto-selected wallet may mismatch the gig's payment coin
When payment_currency / merchant_wallet_address are absent (poster-initiated flow), the backend looks up the worker's wallet with w.currency === gigCoin using strict equality. The frontend walletMatchesCoin helper uses a broader rule: it also accepts currencies whose key starts with ${want}_ (e.g. "usdc_sol" matches gig coin "USDC"). If preferredCoinToPaymentCurrency maps "USDC" to a canonical key that differs from the wallet's .currency field, the .find() silently fails and the code falls back to workerWallets[0], which could be a completely different coin. The poster then creates a CoinPay invoice denominated in the wrong currency without any warning.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Fixes #478.
When the poster initiates an invoice on behalf of the worker, the frontend no longer forces the poster to select a CoinPay receiving wallet (which they wouldn't have access to). The backend API now automatically falls back to selecting the worker's CoinPay wallet matching the gig's payment coin.