From bc8a2a8a711b3d8f67f43ad912e03b13cbb35151 Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Wed, 8 Jul 2026 01:03:16 +0100 Subject: [PATCH] feat(bounty): don't require the caller's personal wallet for MANAGED payout/cancel Mirror the hackathon use-publish-winners flow: the backend now signs select_winners / cancel with the on-chain event manager (the org treasury or owner that published), so a connected wallet is only needed for EXTERNAL signing. Stop blocking MANAGED on a personal wallet and send ownerAddress as an optional hint. Pairs with boundless-nestjs#392. --- hooks/use-bounty-cancel.ts | 20 +++++++++++--------- hooks/use-bounty-payout.ts | 21 ++++++++++++--------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/hooks/use-bounty-cancel.ts b/hooks/use-bounty-cancel.ts index 156f5904..5c8ad53f 100644 --- a/hooks/use-bounty-cancel.ts +++ b/hooks/use-bounty-cancel.ts @@ -77,19 +77,21 @@ export const useBountyCancel = ({ const cancel = async (): Promise => { if (!organizationId || !bountyId) return; - if (!ownerAddress) { - toast.error( - isExternal - ? 'Connect a wallet to sign the cancellation.' - : 'Please connect your wallet first' - ); + // EXTERNAL is signed by the connected wallet; MANAGED is signed server-side + // by the on-chain event manager (the treasury/owner that published), so no + // connected wallet is needed. ownerAddress is a hint the backend may use as + // a fallback. + if (isExternal && !ownerAddress) { + toast.error('Connect a wallet to sign the cancellation.'); return; } - const body: CancelBountyEscrowRequest = { - ownerAddress, + // ownerAddress is optional on the backend (boundless-nestjs#392); until + // codegen picks that up the generated type marks it required, so cast. + const body = { fundingMode, - }; + ...(ownerAddress ? { ownerAddress } : {}), + } as CancelBountyEscrowRequest; finalizedRef.current = false; toast.info('Submitting cancellation…'); diff --git a/hooks/use-bounty-payout.ts b/hooks/use-bounty-payout.ts index 3d1e97bf..f91ad8b3 100644 --- a/hooks/use-bounty-payout.ts +++ b/hooks/use-bounty-payout.ts @@ -72,20 +72,23 @@ export const useBountyPayout = ({ selections: BountyWinnerSelection[] ): Promise => { if (!organizationId || !bountyId || selections.length === 0) return; - if (!ownerAddress) { - toast.error( - isExternal - ? 'Connect a wallet to sign the payout.' - : 'Please connect your wallet first' - ); + // EXTERNAL is signed by the connected wallet, so it's required there. + // MANAGED is signed server-side by the on-chain event manager (the treasury + // / owner that published) — no connected wallet needed. ownerAddress is a + // hint only; the backend resolves and signs with the real manager. + if (isExternal && !ownerAddress) { + toast.error('Connect a wallet to sign the payout.'); return; } - const body: SelectBountyWinnersRequest = { - ownerAddress, + // ownerAddress is optional on the backend (it resolves the manager); until + // codegen picks that up (boundless-nestjs#392) the generated type still + // marks it required, so cast. + const body = { selections, fundingMode, - }; + ...(ownerAddress ? { ownerAddress } : {}), + } as SelectBountyWinnersRequest; finalizedRef.current = false; toast.info('Submitting winner selection…');