Skip to content

Commit bdfbc5b

Browse files
sktbrdclaude
andcommitted
fix(poidh): add all V3 custom errors to ABI + human-readable error messages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7fecf8d commit bdfbc5b

2 files changed

Lines changed: 73 additions & 2 deletions

File tree

src/hooks/usePoidhContract.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,44 @@ function buildPoidhReturn(state: PoidhWriteState) {
6969
};
7070
}
7171

72+
const POIDH_ERROR_MESSAGES: Record<string, string> = {
73+
AlreadyVoted: "You have already voted on this claim.",
74+
ClaimNotFound: "Claim not found on-chain. Make sure you're on the right network.",
75+
BountyNotFound: "Bounty not found on-chain.",
76+
VotingOngoing: "Voting is still in progress — wait for the deadline to resolve.",
77+
VotingEnded: "The voting period has ended.",
78+
NoVotingPeriodSet: "No voting period is active for this bounty.",
79+
BountyClaimed: "This bounty has already been claimed.",
80+
BountyClosed: "This bounty is closed.",
81+
WrongCaller: "You are not allowed to perform this action.",
82+
IssuerCannotClaim: "The bounty creator cannot submit a claim.",
83+
IssuerCannotWithdraw: "The bounty creator cannot withdraw as a contributor.",
84+
NotActiveParticipant: "You are not a participant in this bounty.",
85+
NotOpenBounty: "This action is only available for open bounties.",
86+
NotSoloBounty: "This action is only available for solo bounties.",
87+
ClaimAlreadyAccepted: "This claim has already been accepted.",
88+
NothingToWithdraw: "Nothing to withdraw.",
89+
MaxParticipantsReached: "This bounty has reached its maximum number of participants.",
90+
NotCancelledOpenBounty: "This bounty has not been cancelled.",
91+
VoteWouldPass: "Cannot reset — the vote would pass. Resolve it instead.",
92+
MinimumBountyNotMet: "Amount is below the minimum required to create a bounty.",
93+
MinimumContributionNotMet: "Amount is below the minimum required to contribute.",
94+
NoEther: "No ETH sent.",
95+
ContractsCannotCreateBounties: "Smart contracts cannot create bounties directly.",
96+
TransferFailed: "ETH transfer failed.",
97+
InsufficientBalance: "Insufficient balance.",
98+
};
99+
100+
function decodePoidhError(err: unknown): Error {
101+
if (!(err instanceof Error)) return new Error(String(err));
102+
const msg = err.message;
103+
for (const [name, friendly] of Object.entries(POIDH_ERROR_MESSAGES)) {
104+
if (msg.includes(name)) return new Error(friendly);
105+
}
106+
// Fallback: trim the noisy viem stack to the first line
107+
return new Error(msg.split("\n")[0]);
108+
}
109+
72110
async function assertPoidhReady(ctx: ReturnType<typeof usePoidhContext>, chainId: number) {
73111
if (!ctx.isConnected) throw new Error("Connect your wallet first");
74112
if (!ctx.contractAddress) throw new Error(`Unsupported chain: ${chainId}`);
@@ -113,7 +151,7 @@ async function sendAndConfirm(
113151
state.setIsSuccess(true);
114152
return txHash;
115153
} catch (err) {
116-
state.setError(err instanceof Error ? err : new Error(String(err)));
154+
state.setError(decodePoidhError(err));
117155
throw err;
118156
} finally {
119157
state.setIsPending(false);

src/lib/poidh/abi.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,5 +182,38 @@ export const POIDH_ABI = [
182182
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
183183
"stateMutability": "view",
184184
"type": "function"
185-
}
185+
},
186+
// ── Custom errors ────────────────────────────────────────────────────────
187+
{ "inputs": [], "name": "NoEther", "type": "error" },
188+
{ "inputs": [], "name": "MinimumBountyNotMet", "type": "error" },
189+
{ "inputs": [], "name": "MinimumContributionNotMet", "type": "error" },
190+
{ "inputs": [], "name": "BountyNotFound", "type": "error" },
191+
{ "inputs": [], "name": "ClaimNotFound", "type": "error" },
192+
{ "inputs": [], "name": "VotingOngoing", "type": "error" },
193+
{ "inputs": [], "name": "VotingEnded", "type": "error" },
194+
{ "inputs": [], "name": "NoVotingPeriodSet", "type": "error" },
195+
{ "inputs": [], "name": "BountyClaimed", "type": "error" },
196+
{ "inputs": [], "name": "BountyClosed", "type": "error" },
197+
{ "inputs": [], "name": "NotOpenBounty", "type": "error" },
198+
{ "inputs": [], "name": "NotSoloBounty", "type": "error" },
199+
{ "inputs": [], "name": "WrongCaller", "type": "error" },
200+
{ "inputs": [], "name": "IssuerCannotClaim", "type": "error" },
201+
{ "inputs": [], "name": "IssuerCannotWithdraw", "type": "error" },
202+
{ "inputs": [], "name": "NotActiveParticipant", "type": "error" },
203+
{ "inputs": [], "name": "AlreadyVoted", "type": "error" },
204+
{ "inputs": [], "name": "ClaimAlreadyAccepted", "type": "error" },
205+
{ "inputs": [], "name": "NothingToWithdraw", "type": "error" },
206+
{ "inputs": [], "name": "TransferFailed", "type": "error" },
207+
{ "inputs": [], "name": "InsufficientBalance", "type": "error" },
208+
{ "inputs": [], "name": "MaxParticipantsReached", "type": "error" },
209+
{ "inputs": [], "name": "NotCancelledOpenBounty", "type": "error" },
210+
{ "inputs": [], "name": "VoteWouldPass", "type": "error" },
211+
{ "inputs": [], "name": "InvalidStartClaimIndex", "type": "error" },
212+
{ "inputs": [], "name": "ContractsCannotCreateBounties", "type": "error" },
213+
{ "inputs": [], "name": "InvalidTreasury", "type": "error" },
214+
{ "inputs": [], "name": "InvalidPoidhNft", "type": "error" },
215+
{ "inputs": [], "name": "InvalidWithdrawTo", "type": "error" },
216+
{ "inputs": [], "name": "DirectEtherNotAccepted", "type": "error" },
217+
{ "inputs": [], "name": "InvalidMinBountyAmount", "type": "error" },
218+
{ "inputs": [], "name": "InvalidMinContribution", "type": "error" }
186219
] as const;

0 commit comments

Comments
 (0)