poidh-bounty
Post bounties, discover and inspect bounties, submit claims, evaluate submissions, and accept or nominate winning claims on poidh (pics or it didn't happen) on Ethereum Mainnet, Arbitrum, or Base. Use this skill when the user wants to create a bounty on poidh.xyz, find available bounties, post a task with an ETH reward on-chain, submit proof to an existing bounty, evaluate submissions using vision or other content tools, accept a winning claim on a solo bounty, initiate/resolve voting on an open bounty, query poidh data, or withdraw bounty winnings.
日本語の概要は準備中です。原文の説明を表示しています。
実行スコア 未検証
インストール方法を見る含まれるファイル(200)
- SKILL.md65.3 KB
- .env.example781 B
- .eslintrc.js845 B
- .github/issue-branch.yml235 B
- .github/workflows/create-branch.yml292 B
- .github/workflows/issue-autolink.yml337 B
- .github/workflows/lint.yml993 B
- .github/workflows/release-please.yml438 B
- .gitignore518 B
- .husky/commit-msg82 B
- .husky/post-merge55 B
- .husky/pre-commit57 B
- .nvmrc9 B
- .prettierignore526 B
- .prettierrc.js121 B
- .vscode/css.code-snippets191 B
- .vscode/extensions.json190 B
- .vscode/settings.json499 B
- .vscode/typescriptreact.code-snippets5.2 KB
- commitlint.config.js435 B
- jest.config.js1.3 KB
- jest.setup.js339 B
- LICENSE1.1 KB
- migrations/001_create_ban_table.sql374 B
- migrations/002_create_bounty_extra_table.sql160 B
- migrations/003_rename_category_bounty_extra_table.sql69 B
- migrations/004_add_usd_price_table.sql192 B
- migrations/005_create_notification_tokens_table.sql276 B
- migrations/006_delete_notification_tokens_table.sql50 B
- migrations/007_create_comments_table.sql780 B
- migrations/008_create_user_extra_table.sql415 B
- migrations/009_create_reactions_table.sql655 B
- migrations/010_create_notifications_table.sql246 B
- migrations/011_add_amount_sort_bounty_extra_table.sql86 B
- migrations/012_add_wei_users_extra_table.sql61 B
- migrations/013_add_farcaster_fid_users_extra.sql74 B
- migrations/014_add_gwei_users_extra_table.sql62 B
- migrations/015_add_neynar_last_updated_users_extra.sql85 B
- migrations/016_create_auth_tables.sql484 B
- next-env.d.ts201 B
- next-sitemap.config.js353 B
- next.config.js2.2 KB
- neynar.ts649 B
- notifications.db20.0 KB
- package.json4.3 KB
- pnpm-lock.yaml712.3 KB
- postcss.config.js83 B
- prisma.config.ts247 B
- prisma/prisma.ts1.3 KB
- prisma/schema.prisma7.1 KB
- public/agents.txt63 B
- public/favicon.ico15.0 KB
- public/favicon/about.txt378 B
- public/favicon/android-chrome-192x192.png15.6 KB
- public/favicon/android-chrome-512x512.png46.6 KB
- public/favicon/apple-touch-icon.png13.9 KB
- public/favicon/favicon-16x16.png824 B
- public/favicon/favicon-32x32.png1.9 KB
- public/favicon/site.webmanifest376 B
- public/fonts/GeistMono-Black.woff240.7 KB
- public/fonts/GeistMono-Bold.ttf93.1 KB
- public/fonts/GeistMono-Bold.woff240.6 KB
- public/fonts/GeistMono-Light.woff239.6 KB
- public/fonts/GeistMono-Medium.woff240.3 KB
- public/fonts/GeistMono-Regular.ttf93.2 KB
- public/fonts/GeistMono-Regular.woff239.3 KB
- public/fonts/GeistMono-SemiBold.woff240.4 KB
- public/fonts/GeistMono-Thin.woff237.7 KB
- public/fonts/GeistMono-UltraBlack.woff240.6 KB
- public/fonts/GeistMono-UltraLight.woff239.5 KB
- public/fonts/GeistMonoVariableVF.woff252.2 KB
- public/fonts/inter-var-latin.woff235.7 KB
- public/fonts/PixeloidSans-Regular.ttf104.2 KB
- public/icon.png149.8 KB
- public/images/avatar.png5.1 KB
- public/images/create-wallet-icon.png18.3 KB
- public/images/farcaster_arch.svg890 B
- public/images/poidh-preview-hero-v1.png128.1 KB
- public/images/poidh-preview-hero-v2.png180.5 KB
- public/images/unknown.png7.7 KB
- public/images/zerodev-logo.svg4.3 KB
- public/llms.txt643 B
- public/Logo_poidh.svg13.3 KB
- public/mini-splash-v2.png6.7 KB
- public/poidh logo transparent.png59.9 KB
- public/splash.png8.2 KB
- README.md6.3 KB
- renovate.json279 B
- scripts/backfillBountiesAlbums.ts2.4 KB
- scripts/data/backfill_bounties_albums.csv18.6 KB
- scripts/migration.ts2.5 KB
- scripts/sync-skill.mjs319 B
- src/__tests__/addToAlbum.test.ts3.2 KB
- src/__tests__/authConfig.test.ts1.7 KB
- src/__tests__/authRouter.test.ts4.8 KB
- src/__tests__/banSignature.test.ts6.0 KB
- src/__tests__/runWithSession.test.ts2.8 KB
- src/__tests__/session.test.ts925 B
- src/__tests__/stripLegacyCommentPrefix.test.ts952 B
- src/__tests__/wagmiConfig.test.ts3.9 KB
- src/app/.well-known/farcaster.json/route.ts1.6 KB
- src/app/(home)/HomePage.tsx8.7 KB
- src/app/(home)/homeParams.ts575 B
- src/app/(home)/layout.tsx1.2 KB
- src/app/(home)/page.tsx957 B
- src/app/[netname]/bounty/[id]/BountyPage.tsx6.0 KB
- src/app/[netname]/bounty/[id]/data/route.ts10.8 KB
- src/app/[netname]/bounty/[id]/layout.tsx249 B
- src/app/[netname]/bounty/[id]/page.tsx1.2 KB
- src/app/a/[album]/layout.tsx286 B
- src/app/a/[album]/page.tsx8.3 KB
- src/app/account/[address]/data/route.ts32.9 KB
- src/app/account/[address]/layout.tsx260 B
- src/app/account/[address]/page.tsx1.8 KB
- src/app/analytics/page.tsx1.5 KB
- src/app/api/analytics/route.ts4.0 KB
- src/app/api/analytics/transactions/route.ts4.7 KB
- src/app/api/generate-claim-card/route.tsx4.5 KB
- src/app/api/mcp/__tests__/route.test.ts3.2 KB
- src/app/api/mcp/route.ts5.0 KB
- src/app/api/og/account/route.tsx11.7 KB
- src/app/api/og/album/route.tsx2.7 KB
- src/app/api/og/analytics/route.tsx5.2 KB
- src/app/api/og/bounty/route.tsx5.2 KB
- src/app/api/trpc/[trpc]/route.ts941 B
- src/app/bounties/data/route.ts1.8 KB
- src/app/error.tsx1.3 KB
- src/app/explore/layout.tsx256 B
- src/app/explore/page.tsx7.0 KB
- src/app/feed/layout.tsx247 B
- src/app/feed/page.tsx8.4 KB
- src/app/layout.client.tsx1.2 KB
- src/app/layout.tsx4.6 KB
- src/app/leaderboard/layout.tsx270 B
- src/app/leaderboard/page.tsx24.5 KB
- src/app/not-found.tsx561 B
- src/app/privacy/page.tsx20.5 KB
- src/app/terms/layout.tsx233 B
- src/app/terms/page.tsx25.1 KB
- src/app/tx/page.tsx930 B
- src/app/tx/TxApproval.tsx14.0 KB
- src/components/account/AccountInfo.tsx15.0 KB
- src/components/account/ClaimListAccount.tsx3.0 KB
- src/components/account/PendingRefunds.tsx6.9 KB
- src/components/account/sections.ts371 B
- src/components/account/ShareAccountModal.tsx1.8 KB
- src/components/account/UserList.tsx3.9 KB
- src/components/account/ZkPassportVerify.tsx7.2 KB
- src/components/albums/AlbumList.tsx2.0 KB
- src/components/AnalyticsDashboard.tsx28.0 KB
- src/components/auth/chains.ts5.4 KB
- src/components/auth/kernelClient.ts3.6 KB
- src/components/auth/SessionProvider.tsx6.1 KB
- src/components/auth/sheet/AuthAccountView.tsx11.0 KB
- src/components/auth/sheet/AuthAnychainView.tsx38.6 KB
- src/components/auth/sheet/AuthApprovalView.tsx40.9 KB
- src/components/auth/sheet/AuthSignInView.tsx11.4 KB
- src/components/auth/sheet/SendFundsSection.tsx19.7 KB
- src/components/auth/SignInModal.tsx3.3 KB
- src/components/auth/TurnkeyExportCard.tsx11.1 KB
- src/components/auth/types.ts1.2 KB
- src/components/auth/ZeroDevAuthModal.tsx5.4 KB
- src/components/bounty/AcceptClaimConfirm.tsx2.1 KB
- src/components/bounty/BountyClaims.tsx3.7 KB
- src/components/bounty/BountyHistory.tsx2.9 KB
- src/components/bounty/BountyInfo.tsx21.5 KB
- src/components/bounty/BountyItem.tsx3.5 KB
- src/components/bounty/BountyList.tsx2.4 KB
- src/components/bounty/BountyMultiplayer.tsx2.6 KB
- src/components/bounty/BountySuccessModal.tsx7.6 KB
- src/components/bounty/ClaimRefund.tsx3.2 KB
- src/components/bounty/CommentsSection.tsx18.9 KB
- src/components/bounty/ConfirmBountySuccessModal.tsx10.3 KB
- src/components/bounty/FormBounty.tsx41.3 KB
- src/components/bounty/FormJoinBounty.tsx14.1 KB
- src/components/bounty/HowItWorksModal.tsx4.2 KB
- src/components/bounty/JoinBounty.tsx1.6 KB
- src/components/bounty/JoinBountySuccessModal.tsx8.1 KB
- src/components/bounty/NftList.tsx2.8 KB
- src/components/bounty/PastBountyCard.tsx4.6 KB
- src/components/bounty/ShareBountyModal.tsx2.3 KB
- src/components/bounty/SubmitVotingConfirm.tsx2.8 KB
- src/components/bounty/Voting.tsx16.6 KB
- src/components/bounty/Withdraw.tsx3.1 KB
- src/components/claims/ClaimCard.tsx20.7 KB
- src/components/claims/ClaimConfirm.tsx2.1 KB
- src/components/claims/ClaimItem.tsx9.7 KB
- src/components/claims/ClaimList.tsx3.1 KB
- src/components/claims/ClaimMediaParts.tsx4.6 KB
- src/components/claims/ClaimSuccessModal.tsx8.5 KB
- src/components/claims/FormClaim.tsx18.4 KB
- src/components/feed/Activity.tsx15.5 KB
- src/components/feed/ClaimImageEmbed.tsx4.4 KB
- src/components/feed/HomeHeading.tsx1.8 KB
- src/components/feed/LatestClaimImages.tsx5.4 KB
- src/components/feed/RecentPayouts.tsx6.2 KB
- src/components/global/__tests__/WebMcpTools.test.tsx6.3 KB
- src/components/global/AnalyticsTicker.tsx7.8 KB
- src/components/global/ButtonCTA.tsx363 B
- src/components/global/ClaimFundsButton.tsx8.5 KB
SKILL.md(原文)
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Overview
This skill interacts with poidh across Ethereum Mainnet, Arbitrum, and Base.
It can:
- Discover bounties
- Read bounty and claim data
- Post bounties — solo or open
- Submit claims
- Evaluate claim submissions
- Accept winning claims on solo bounties
- Initiate and resolve contributor voting on open bounties
- Withdraw bounty winnings
poidh ("pics or it didn't happen") is an onchain bounty protocol.
A bounty issuer escrows ETH and describes an outcome. Claimants submit proof that they completed the bounty. The issuer — or contributors through weighted voting — can accept a winning claim and release the bounty payout.
Official Documentation
poidh's official documentation is available at:
https://docs.poidh.xyz/
Use the documentation for deeper explanations of the poidh.xyz website, how it works, concepts, protocol behavior, reputation systems, and product terminology.
This SKILL.md is the primary operational guide for agent actions, data discovery, transaction safety, and interacting with the poidh.xyz website and the underlying poidh protocol smart contracts.
MCP Server
poidh.xyz also runs a remote MCP server for agents that support the Model Context Protocol:
https://poidh.xyz/api/mcp
Transport: Streamable HTTP, stateless, no authentication.
| Tool | Does |
|---|---|
find_bounties | List open bounties, or search all bounties by text |
get_bounty | Complete bounty data: status, all claims, comments, winner, voting state and identities |
get_account | Complete public profile/activity data: bounties, claims, NFTs, comments, score and related users |
get_leaderboard | Leaderboard by points |
prepare_create_bounty | Unsigned tx: post a solo or open bounty |
prepare_join_bounty | Unsigned tx: add funds to an open bounty |
prepare_submit_claim | Unsigned tx: submit a claim (see the URI rules below) |
prepare_accept_claim | Unsigned tx: accept a claim, or start a vote when contributors exist |
prepare_vote | Unsigned tx: vote on the claim under vote |
prepare_resolve_vote | Unsigned tx: resolve a finished vote |
prepare_withdraw | Unsigned tx: withdraw winnings |
The MCP server never signs or holds keys. prepare_* tools return:
transaction:{ chainId, to, data, value }foreth_sendTransactionwalletSendCalls: the same call as an EIP-5792wallet_sendCallsrequestsimulation: aneth_calldry run when you passfrom, with decoded contract errorssignUrl: ahttps://poidh.xyz/tx?...link to send a human who wants to review and approve the action on poidh.xyz with the wallet they already use there, including poidh's built-in wallet
The tools take the bounty ID shown in the poidh.xyz URL and convert it to the contract ID for you. They refuse to act on poidh v2 bounties (see Frontend IDs vs Contract IDs) and return an error instead of a transaction. The rules in this guide still apply: confirm with the user before signing, and only regular wallets (EOAs) can create bounties.
WebMCP (in-browser agents)
When an agent runs inside a browser on poidh.xyz (Chrome's WebMCP, ChatGPT desktop site tools), the page registers the same tools through document.modelContext. find_bounties and get_bounty return data. The action tools (create_bounty, join_bounty, submit_claim, accept_claim, vote, resolve_vote, withdraw) open the /tx approval page, where the person approves in their own wallet.
Open-Source Repository
The poidh.xyz application is open source.
Official repository:
https://github.com/picsoritdidnthappen/poidh-app
poidh.xyz is the primary user interface and access point for the poidh protocol, but poidh.xyz is not the poidh protocol itself.
The poidh protocol consists of deployed onchain smart contracts and the resulting onchain state.
The poidh.xyz frontend provides a convenient interface for:
- discovering bounties
- creating and funding bounties
- submitting claims
- viewing claim media
- participating in bounty voting
- viewing profiles and account activity
- reading comments and other social context
- accessing structured
/dataendpoints
Agents, alternative frontends, scripts, applications, and other interfaces may interact with the poidh protocol without using poidh.xyz directly.
The open-source poidh.xyz repository is useful for understanding how the primary frontend:
- reads and presents protocol data
- resolves claim media
- displays bounty and voting state
- calculates and presents profile information
- exposes public
/dataendpoints - integrates offchain social and identity information
- interacts with the poidh indexer and deployed contracts
Do not assume that behavior or data produced by the poidh.xyz frontend is itself authoritative protocol state.
For consensus-critical information such as:
- whether a bounty is active, canceled, or finalized
- accepted claims
- contributor voting state
- balances
- pending withdrawals
- payout state
- authorization
- transaction validity
the deployed smart contracts and current onchain state are authoritative.
The poidh.xyz frontend, its JSON endpoints, and the poidh indexer are interfaces and derived data sources built around the protocol.
Claim Proof and the URI Field
A poidh claim contains:
- a name
- a description
- a proof URI
The proof URI is the value poidh.xyz uses to resolve the media attached to the claim.
Do not treat the URI field as a generic evidence-link field.
Links to supporting material such as:
- X / Twitter posts
- Farcaster posts
- GitHub repositories or pull requests
- webpages
- benchmark pages
- documentation
- transaction explorer pages
should normally be placed in the claim description.
The smart contract accepts an arbitrary string for the URI field, but that does not mean an arbitrary URL will display properly on poidh.xyz.
Media Types Supported by poidh.xyz
The poidh smart contract does not enforce a file type for the claim URI. The frontend determines whether the URI can actually be displayed.
Images uploaded through poidh.xyz
The normal poidh.xyz claim form currently accepts:
.jpg.jpeg.png.gif.webp
The normal poidh.xyz upload flow:
- uploads the image file to IPFS
- creates metadata containing the uploaded image URI
- uploads that metadata to IPFS
- submits the resulting IPFS-hosted metadata URI to the poidh contract
Therefore, a claim created through the normal poidh.xyz interface will commonly have a URI pointing to metadata, not directly to the image file.
Do not invent or reconstruct this URI. Use the URI actually returned by the upload flow.
Claims submitted directly through the contract
Direct contract submissions do not have to use the poidh.xyz upload flow or IPFS.
The current poidh.xyz frontend knows how to display the following claim media:
Direct images
A directly accessible URL whose HTTP Content-Type begins with:
image/
For maximum compatibility, prefer the same image formats accepted by the native poidh.xyz uploader:
.jpg
.jpeg
.png
.gif
.webp
Direct videos
A directly accessible URL whose HTTP Content-Type begins with:
video/
The frontend also explicitly recognizes these video extensions:
.mp4
.mov
.webm
.ogg
JSON metadata
The frontend can resolve JSON metadata containing an image field:
{
"image": "<MEDIA_URL>"
}
The media URL referenced by that field should itself resolve to displayable image or video media.
The current frontend should not be assumed to render arbitrary PDFs, documents, GitHub pages, social posts, ordinary HTML pages, benchmark pages, or other generic URLs as claim media.
Those resources may still be valid supporting evidence, but their links belong in the claim description unless they resolve to supported media as described above.
URI Rule
Contract-valid is not the same thing as frontend-displayable.
Before submitting a claim directly through the contract:
- choose a real, accessible URI
- verify that it resolves to supported media or supported JSON metadata
- verify that poidh.xyz can display the resulting claim media
- put non-media supporting links in
CLAIM_DESCRIPTION
Never invent, guess, or use a placeholder URI.
Contract Immutability
The deployed poidh v3 contracts are immutable.
They cannot be upgraded or modified after deployment.
This has two important consequences:
- integrations do not need to account for proxy upgrades or implementation changes at these addresses
- known contract behavior — including known getter bugs — remains part of the deployed contract unless a new contract is deployed
Do not assume a documented contract bug has been fixed merely because the frontend behaves correctly.
Always verify which contract address is being used.
Supported Networks
The actively supported poidh networks for this skill are:
- Ethereum Mainnet
- Arbitrum
- Base
All bounty funding and payouts on these networks use ETH.
Retired Network: Degen Chain
Degen Chain (chainId 666666666) is retired and is not a supported poidh network.
Historical poidh activity from Degen Chain may still appear:
- on historical poidh.xyz bounty pages
- in the poidh indexer
- in profile and leaderboard data
- in analytics
- in historical datasets
- in old links or documentation
Treat all Degen Chain records as historical, read-only data.
🚨 DO NOT CREATE BOUNTIES, SUBMIT CLAIMS, CONTRIBUTE FUNDS, ACCEPT CLAIMS, VOTE, WITHDRAW FUNDS, OR ATTEMPT ANY OTHER WRITE OPERATION ON DEGEN CHAIN.
Do not attempt to switch the user's wallet to Degen Chain or request a Degen RPC URL.
If an indexer or frontend endpoint returns a Degen Chain bounty, do not treat it as an actionable bounty even if its historical status appears open.
If the user provides a historical Degen bounty URL, the skill may inspect available frontend or indexer data for historical purposes, but must clearly state that Degen Chain is retired and that no transaction can be performed through this skill.
poidh v3 Core Contracts
| Chain | Core Contract | Explorer |
|---|---|---|
| Ethereum Mainnet | 0xE731dFadBFf20542E10D09D26Fc71445C70d4232 | https://etherscan.io/address/0xe731dfadbff20542e10d09d26fc71445c70d4232 |
| Arbitrum | 0x5555Fa783936C260f77385b4E153B9725feF1719 | https://arbiscan.io/address/0x5555fa783936c260f77385b4E153B9725fef1719 |
| Base | 0x5555Fa783936C260f77385b4E153B9725feF1719 | https://basescan.org/address/0x5555fa783936c260f77385b4E153B9725fef1719 |
poidh v3 NFT Contracts
Claim proof NFTs are minted through the poidh NFT contracts.
| Chain | NFT Contract |
|---|---|
| Ethereum Mainnet | 0x9c5f45d5e1382e4058d334d93c6c01442012a4d9 |
| Arbitrum | 0x27e117cc9a8da363442e7bd0618939e3eeeacf6a |
| Base | 0x27e117cc9a8da363442e7bd0618939e3eeeacf6a |
The NFT contract can also be resolved dynamically from the core contract:
cast call $POIDH_CONTRACT_ADDRESS \
"poidhNft()(address)" \
--rpc-url $RPC_URL
Prefer resolving it dynamically when interacting with a live contract.
🚨 Never Use poidh v2 Contracts
poidh v3 is a security-focused rebuild of the protocol following an exploit affecting poidh v2 in December 2025.
Historical poidh v2 activity may still appear:
- on poidh.xyz
- in the indexer
- in analytics
- in historical datasets
- in old documentation
The v2 contracts are retained only as historical onchain records.
🚨 DO NOT CREATE BOUNTIES, SUBMIT CLAIMS, SEND FUNDS, OR OTHERWISE INTERACT WITH POIDH V2 CONTRACTS.
This skill must only perform write operations against the poidh v3 contracts listed above.
If a contract address does not match a supported v3 deployment, stop and verify it before sending a transaction.
🚨 Known poidh v3 Pagination Bug
The following convenience getters in the currently deployed poidh v3 contracts do not implement working offset pagination:
getBounties(uint256 offset)
getClaimsByBountyId(
uint256 bountyId,
uint256 offset
)
getBountiesByUser(
address user,
uint256 offset
)
getClaimsByUser(
address user,
uint256 offset
)
Do not use these functions to exhaustively enumerate protocol data.
For collections larger than 10 rows, they may repeatedly return the same newest 10 records while older records remain unreachable through the getter.
This is especially dangerous when evaluating claims because older submissions may include:
- the earliest submission
- the first valid submission
- the actual winner under the bounty rules
Never:
getClaimsByBountyId(bountyId, 0)
getClaimsByBountyId(bountyId, 10)
getClaimsByBountyId(bountyId, 20)
and assume those are different pages.
They are not reliable pagination.
Instead: walk the index
The public array getters are exact when the RPC call succeeds. Read indexes from 0
upward and read each referenced record by id:
bountyClaims(uint256 bountyId, uint256 index) returns (uint256 claimId)
claims(uint256 claimId) returns (
uint256 id, address issuer, uint256 bountyId, address bountyIssuer,
string name, string description, uint256 createdAt, bool accepted
)
Do not treat a failed indexed read as proof that the array ended.
A provider may surface an out-of-bounds revert, rate limit, transport failure, unsupported
method, or other RPC problem through the same generic client exception. A bare
catch { break; } can therefore silently truncate an array or turn a non-empty array into
an empty one.
Use this rule:
- read
bountyClaims(bountyId, i)from the current provider - if it returns a claim ID, record it and continue
- if it fails, retry the same exact
(bountyId, i)read through a genuinely independent RPC provider - verify the second provider is healthy with at least one known-good read
- if the independent provider returns a claim ID, the first provider failed; continue the walk
- only treat index
ias the end when a healthy independent provider also reports that the same index is unavailable - if no independent provider is available, fail loudly and do not claim the enumeration was exhaustive
Conceptual example:
async function walkBountyClaims(primary, secondary, bountyId) {
const ids = [];
for (let i = 0; ; i++) {
try {
ids.push(await primary.bountyClaims(bountyId, i));
continue;
} catch (primaryError) {
// Confirm the exact same index through independent infrastructure.
// `knownGoodRead` must be a call whose successful result is already known.
await knownGoodRead(secondary);
try {
ids.push(await secondary.bountyClaims(bountyId, i));
continue; // primary failed; this index exists
} catch (secondaryError) {
// Both providers report this exact index unavailable.
// Treat this as the boundary only after the secondary provider passed
// the known-good health check above.
break;
}
}
}
return ids;
}
The independent provider must be genuinely independent infrastructure. A second URL or transport that ultimately reaches the same RPC host is not a meaningful second opinion.
Apply the same boundary-confirmation rule to userClaims(user, i) and
userBounties(user, i).
The same shape replaces all four broken getters:
| Do not use | Exact replacement |
|---|---|
getBounties(offset) | bountyCounter(), then bounties(id) for each id |
getClaimsByBountyId(bountyId, offset) | bountyClaims(bountyId, i) walked to an independently confirmed boundary, then claims(id) |
getBountiesByUser(user, offset) | userBounties(user, i) walked to an independently confirmed boundary, then bounties(id) |
getClaimsByUser(user, offset) | userClaims(user, i) walked to an independently confirmed boundary, then claims(id) |
A returned row is not necessarily a record
The same convenience getters allocate a fixed array of 10 and never shrink it, so short
results are zero-padded. Never treat result.length as the number of real records, and do
not attempt to repair these convenience getters by filtering their output.
Use the exact index-based replacements above for enumeration instead.
Data Source Trust Hierarchy
poidh exposes several ways to obtain data.
Use the source appropriate to the task.
1. Onchain State — Authoritative
Use direct contract calls for:
- bounty status
- payout decisions
- claim acceptance
- voting state
- balances
- issuer authorization
- finalization state
- critical real-time checks
- anything immediately preceding a transaction
For critical decisions, the contract is the source of truth.
2. Onchain Indexes and Events — Authoritative Historical Discovery
For targeted exhaustive reads, prefer the contract's public index getters:
bountyClaims(bountyId, i)for claims on one bountyuserBounties(user, i)for bounties associated with one useruserClaims(user, i)for claims associated with one userbountyCounter()+bounties(id)for the complete bounty registryclaimCounter()+claims(id)for the complete claim registry
Walk array indexes from 0 upward. If an indexed read fails, confirm the same exact
index through a healthy independent RPC provider before treating the failure as the end
of the array. Then read each referenced record by id.
Use contract events for:
- proof URI discovery
- historical event metadata
- transaction history
- alternative exhaustive discovery when a public index is unavailable or inconvenient
For evaluating a single bounty, bountyClaims(bountyId, i) + claims(id) is the preferred
authoritative claim-enumeration path. ClaimCreated events are especially useful for retrieving
the submitted imageUri.
3. poidh Indexer — Convenient and Fast
poidh operates an offchain indexer populated from onchain events.
API documentation:
https://indexer.poidh.xyz/swagger
The indexer is useful for:
- browsing bounties
- browsing claims
- relational queries
- building frontends
- finding candidate records quickly
- avoiding large numbers of RPC calls
The indexer is approximately 99.9% historically accurate, but it is an offchain derived data source.
Therefore:
Use the indexer for discovery and convenience, but verify critical state directly against the contract before transferring funds, accepting claims, submitting votes, or making other consensus-sensitive decisions.
4. poidh JSON Endpoints — Lightweight Discovery
poidh.xyz exposes lightweight frontend JSON endpoints.
These are useful when an agent wants structured bounty data without directly interacting with the indexer or parsing chain events.
They are convenience endpoints, not the ultimate authority for critical contract state.
Common Resource Links
Individual bounty and account /data endpoints include top-level links to additional poidh resources:
docsUrl
githubUrl
These fields have different purposes:
docsUrl— official poidh documentation for deeper explanations of protocol concepts, product behavior, reputation systems, and terminologygithubUrl— source code for the poidh.xyz frontend and its public data endpoints
Current resources:
docsUrl: https://docs.poidh.xyz/
githubUrl: https://github.com/picsoritdidnthappen/poidh-app
When an unfamiliar poidh concept appears in /data, prefer following docsUrl rather than guessing its meaning.
When implementation details of poidh.xyz or its /data endpoints matter, githubUrl points to the open-source frontend repository.
These resources are informational and operational aids. They do not replace direct onchain verification for consensus-critical state or transactions.
Required Environment Variables
| Variable | Description |
|---|---|
PRIVATE_KEY | Private key of the EOA signing transactions, hex with or without 0x |
RPC_URL | RPC URL for the target chain |
POIDH_CHAIN | mainnet, arbitrum, or base |
Do not expose PRIVATE_KEY in output, logs, URLs, command history shown to the user, or error reports.
Resolve Chain Configuration
At the start of an onchain session:
case "$POIDH_CHAIN" in
mainnet)
POIDH_CONTRACT_ADDRESS="0xE731dFadBFf20542E10D09D26Fc71445C70d4232"
POIDH_BASE_URL="https://poidh.xyz/mainnet"
POIDH_V2_OFFSET=0
;;
arbitrum)
POIDH_CONTRACT_ADDRESS="0x5555Fa783936C260f77385b4E153B9725feF1719"
POIDH_BASE_URL="https://poidh.xyz/arbitrum"
POIDH_V2_OFFSET=180
;;
base)
POIDH_CONTRACT_ADDRESS="0x5555Fa783936C260f77385b4E153B9725feF1719"
POIDH_BASE_URL="https://poidh.xyz/base"
POIDH_V2_OFFSET=986
;;
*)
echo "Unknown POIDH_CHAIN: '$POIDH_CHAIN' (expected mainnet, arbitrum, or base)" >&2
exit 1
;;
esac
Frontend IDs vs Contract IDs
A poidh.xyz bounty ID is not always the same as its poidh v3 contract bounty ID.
Historical v2 bounties are included in frontend numbering.
Ethereum Mainnet never had poidh v2, so Mainnet IDs do not require an offset.
Contract ID → Frontend ID
frontend_id = contract_bounty_id + POIDH_V2_OFFSET
Frontend ID → Contract ID
contract_bounty_id = frontend_id - POIDH_V2_OFFSET
Current offsets:
| Chain | Offset |
|---|---|
| Ethereum Mainnet | 0 |
| Arbitrum | 180 |
| Base | 986 |
Example:
Base contract bounty ID: 285
285 + 986 = 1271
Frontend:
https://poidh.xyz/base/bounty/1271
🚨 Never assume
/base/bounty/106corresponds tobounties(106).
Frontend IDs at or below the offset are poidh v2 bounties
On Arbitrum and Base, a frontend ID less than or equal to the offset is a historical poidh v2 bounty. It is read-only: do not join it, claim it, accept a claim, vote, or resolve a vote.
The indexer still reports an onChainId for these bounties, but it is the v2 contract ID. The same number is a different bounty on the v3 contract:
Base frontend 176 → v2 bounty, onChainId 176 (read-only)
Base frontend 1162 → v3 bounty 176 (a different bounty)
🚨 Never pass a v2 bounty's
onChainIdto a v3 contract call. It targets someone else's bounty.
Convert the ID before making contract calls.
Part 1: Discovering Bounties
Agents do not need to scan the entire contract registry just to discover current opportunities.
Use the frontend JSON feed or indexer first.
Recent Open Bounties Feed
Endpoint:
https://poidh.xyz/bounties/data
It returns recent open bounties across poidh.
Default limit:
20
A larger limit can be requested:
https://poidh.xyz/bounties/data?limit=100
Use this endpoint for tasks such as:
- "show me current poidh bounties"
- "find a bounty I can complete"
- "what bounties are open?"
- "find software bounties"
- "find photo bounties"
- "find bounties worth more than X"
After identifying a bounty, inspect its individual data endpoint and/or verify the relevant state onchain.
The frontend feed or indexer may contain historical Degen Chain records.
When discovering actionable bounties, only return bounties on:
- Ethereum Mainnet
- Arbitrum
- Base
Exclude Degen Chain (chainId 666666666) from actionable bounty results even if a historical record appears open.
Individual Bounty JSON
Append:
/data
to a bounty URL.
Format:
https://poidh.xyz/[chain]/bounty/[frontend-bounty-id]/data
Example:
https://poidh.xyz/base/bounty/1271/data
Typical response fields include:
{
"id": 1271,
"onChainId": 285,
"chainId": 8453,
"title": "Best Bounty (July 2026) 🏆",
"description": "Each month, we celebrate the bounty creators...",
"amount": "67000000000000000",
"issuer": "0x4200ac338555e25b20c8fe82ac02a5c8d4e5a5b4",
"createdAt": "1782908709",
"inProgress": true,
"isJoinedBounty": false,
"isCanceled": false,
"isMultiplayer": true,
"isVoting": false,
"deadline": null,
"ban": [],
"extra": {
"bountyId": 1271,
"chainId": 8453,
"album": "poidh"
},
"hasClaims": true,
"hasParticipants": false,
"priceUsd": 125.56135,
"currency": "eth",
"url": "https://poidh.xyz/base/bounty/1271"
}
The individual bounty /data endpoint also returns:
-
claims— all non-banned claims, includingclaimId, the raw claimuri, claimant address, resolved name, Farcaster handle, Twitter handle, poidh profile URL, title, and description.uriis the claim's original proof/metadata URI. It is not necessarily a direct image or video URL and is not pre-resolved by this endpoint. It may point to JSON metadata, direct media, or an IPFS URI/gateway URL. Resolve it using the claim-media rules described below when the actual proof media needs to be inspected. -
comments— all publicly visible (non-deleted) bounty comments in chronological order, including author address, resolved name, Farcaster handle, Twitter handle, poidh profile URL, reply parent, timestamp, and reaction counts.
When evaluating or completing a bounty, always inspect comments for
clarifications, requirement changes, answers from the bounty creator,
or other context that may modify the original bounty description.
Of particular importance:
id
is the frontend bounty ID.
onChainId
is the v3 contract bounty ID.
When available, prefer the returned onChainId rather than manually calculating the offset.
Still verify critical state directly against the contract before a transaction.
Individual Account JSON
Append:
/data
to a poidh account URL.
Format:
https://poidh.xyz/account/[address]/data
Example:
https://poidh.xyz/account/0x4200ac338555e25b20c8fe82ac02a5c8d4e5a5b4/data
The account /data endpoint provides a public machine-readable view of a user's identity, reputation, activity, collection, and social history on poidh.
It may include:
- resolved name, Farcaster handle, Twitter handle, and profile image
- poidh score and aggregate ETH statistics
- historical Degen statistics
- bounties the user created
- bounties the user contributed funds to
- the user's contribution amount and relationship to each bounty
- the creator of each bounty the user interacted with
- current bounty status, including whether it is canceled, completed, or in progress
- whether an active bounty is currently accepting claims
- whether a voting round is currently unresolved
- whether the latest voting round has been resolved
- winning claim and winner information for completed bounties
- claims submitted by the user
- claim submission timestamps when available
- current claim outcome, such as won, pending, not selected, or bounty canceled
- the current state of the bounty associated with each claim
- claim NFTs currently held by the user
- original claimant information for held NFTs
- public, non-deleted comments authored by the user
- comment reply context when available
- users connected to the profile through bounties, claims, NFTs, and comments
poidhScore is poidh's reputation and activity score.
For deeper explanation of poidh concepts and product behavior, see:
https://docs.poidh.xyz/
Bounty records may include fields such as:
status
statusLabel
statusEmoji
acceptingClaims
votingInProgress
voteResolved
winningClaim
creator
url
dataUrl
votingInProgress means the current voting round has started and has not yet been resolved.
A voting deadline may have passed while:
votingInProgress: true
if nobody has yet submitted the vote-resolution transaction.
voteResolved: true
indicates that the latest voting round has been resolved.
Bounty status values may include:
in_progress
completed
canceled
The status emoji mirrors the poidh frontend:
💰 in progress
✅ completed
❌ canceled
The endpoint distinguishes between bounties a user created and bounties they merely funded.
For example:
createdByProfile: false
fundedByProfile: true
means the user contributed funds to a bounty created by somebody else.
The bounty creator identity is included so an agent can follow that relationship to the creator's poidh account.
Completed bounties may include:
winningClaim
with the winning claimant's identity.
Winner identity objects may include:
address
name
farcasterHandle
twitterHandle
pfpUrl
profileUrl
profileDataUrl
This allows an agent to move from one user's activity to the public poidh profile of another user they interacted with.
Claim records may include:
claimStatus
createdAt
currentOwner
bounty
Possible claimStatus values include:
won
pending
not_selected
bounty_canceled
The nested bounty object contains the bounty's current status.
This allows an agent to determine, for example, whether a user submitted a claim to a bounty that:
- is still active and accepting additional claims
- currently has an unresolved voting round
- has been completed
- has been canceled
Full bounty descriptions are included only in the top-level:
bounties
array, which represents bounties the profile created or funded.
Bounty references nested under:
claims
nfts
comments
are intentionally compact.
They generally include the bounty title, current status, creator, winner when applicable, and bounty URLs rather than repeating the full bounty description.
If complete bounty details are needed, follow:
dataUrl
to the bounty's individual /data endpoint.
The:
nfts
array represents claim NFTs currently held by the account.
Do not interpret nfts as a complete historical NFT ownership or transfer record.
The current owner may differ from the original claimant, so NFT records may expose both identities when relevant.
Some claim NFTs may currently be held by a poidh protocol contract.
When this occurs, the identity object may include:
accountType: protocol_contract
isProtocolContract: true
contractLabel
Protocol contracts are not social users.
They do not have poidh profile crawl targets and should not appear in:
relatedUsers
The account endpoint may include:
comments
containing public, non-deleted comments authored by the profile.
Comment records may include:
- comment body
- timestamp
- reply parent
- reply target identity
- upvote and downvote counts
- the related bounty
- the related bounty's current status
- the bounty creator
- the winning claimant when applicable
The endpoint may also include:
relatedUsers
relatedUsers provides convenient crawl targets for the user's public poidh social graph.
Related users may include:
- creators of bounties the profile funded
- creators of bounties the profile submitted claims to
- winners of bounties the profile interacted with
- original claimants of NFTs the profile currently holds
- users the profile replied to in comments
- other publicly visible identities directly connected through poidh activity
Related-user objects may include:
address
name
farcasterHandle
twitterHandle
pfpUrl
profileUrl
profileDataUrl
relationships
relatedBountyUrls
An agent may follow:
profileDataUrl
to inspect another user's public poidh activity and continue traversing the public social graph.
A useful crawl pattern is:
account /data
→ related bounty or related user
→ bounty dataUrl or profileDataUrl
→ additional public poidh context
Historical Degen Chain records may appear in account data.
Degen Chain is retired and must not be treated as an actionable network.
Records may include fields such as:
networkStatus
protocolVersion
liveProtocolSupported
Treat:
networkStatus: retired
or:
liveProtocolSupported: false
as a signal that the record is historical or otherwise not part of the currently supported live protocol.
The account /data endpoint is a convenience representation derived from poidh frontend and indexed data.
Use it for:
- understanding a user's public poidh history
- reputation and activity inspection
- social-graph discovery
- finding bounties a user created or funded
- finding claims a user submitted
- understanding the outcome of those claims
- finding NFTs a user currently holds
- finding public comments authored by a user
- finding related poidh users
- determining the current state of bounties associated with historical user activity
For critical current protocol state, especially immediately before a transaction, verify the relevant state directly onchain.
Part 2: Reading Bounties Directly Onchain
For authoritative bounty state:
cast call $POIDH_CONTRACT_ADDRESS \
"bounties(uint256)(uint256,address,string,string,uint256,address,uint256,uint256)" \
<BOUNTY_ID> \
--rpc-url $RPC_URL
Returns:
id
issuer
name
description
amount
claimer
createdAt
claimId
Typical interpretation:
claimer == 0x0000000000000000000000000000000000000000
Bounty has not been finalized.
claimer == issuer
Bounty was cancelled.
claimer == another address
Bounty has a winning claimant.
Exhaustive Bounty Enumeration
Do not use:
getBounties(offset)
for exhaustive enumeration.
Instead:
cast call $POIDH_CONTRACT_ADDRESS \
"bountyCounter()(uint256)" \
--rpc-url $RPC_URL
Then:
cast call $POIDH_CONTRACT_ADDRESS \
"bounties(uint256)(uint256,address,string,string,uint256,address,uint256,uint256)" \
<BOUNTY_ID> \
--rpc-url $RPC_URL
for each valid registry index.
For ordinary bounty discovery, prefer the JSON feed or indexer rather than scanning the entire registry.
Part 3: Posting a Bounty
Verify Minimum Bounty
Do not hardcode assumptions immediately before a transaction.
Query:
cast call $POIDH_CONTRACT_ADDRESS \
"MIN_BOUNTY_AMOUNT()(uint256)" \
--rpc-url $RPC_URL
Current expected minimum on Mainnet, Arbitrum, and Base:
0.001 ETH
Minimum open-bounty contribution:
cast call $POIDH_CONTRACT_ADDRESS \
"MIN_CONTRIBUTION()(uint256)" \
--rpc-url $RPC_URL
Current expected value:
0.00001 ETH
EOA Requirement
PoidhV3 enforces an EOA requirement for relevant write operations.
Smart contract wallets may revert.
The signing wallet should be an EOA.
Resolve its address with:
cast wallet address --private-key $PRIVATE_KEY
Post a Solo Bounty
Solo bounties are funded only by the issuer.
cast send $POIDH_CONTRACT_ADDRESS \
"createSoloBounty(string,string)" \
"<BOUNTY_NAME>" \
"<BOUNTY_DESCRIPTION>" \
--value <AMOUNT> \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
Example:
cast send $POIDH_CONTRACT_ADDRESS \
"createSoloBounty(string,string)" \
"Brooklyn Bridge at sunset" \
"High quality photo of the Brooklyn Bridge during golden hour. Must show the full span." \
--value 0.001ether \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
Post an Open Bounty
Open bounties allow other wallets to contribute ETH.
cast send $POIDH_CONTRACT_ADDRESS \
"createOpenBounty(string,string)" \
"<BOUNTY_NAME>" \
"<BOUNTY_DESCRIPTION>" \
--value <AMOUNT> \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
If external contributors join, claim acceptance uses contributor-weighted voting.
Get the Bounty ID
After creation, inspect the transaction receipt and decode the bounty creation event.
cast receipt <TX_HASH> \
--rpc-url $RPC_URL \
--json
Do not blindly assume the first log containing multiple topics is the bounty creation event.
Decode the correct event emitted by POIDH_CONTRACT_ADDRESS.
Then:
frontend_id = contract_bounty_id + POIDH_V2_OFFSET
Return both:
- contract bounty ID
- poidh.xyz frontend URL
Part 4: Submitting a Claim
A claimant can submit proof to an eligible active bounty.
The signing wallet cannot be the bounty issuer.
Inspect Bounty First
If given a poidh URL, use its /data endpoint for convenient metadata and onChainId.
Then verify onchain:
cast call $POIDH_CONTRACT_ADDRESS \
"bounties(uint256)(uint256,address,string,string,uint256,address,uint256,uint256)" \
<BOUNTY_ID> \
--rpc-url $RPC_URL
Verify No Vote Is Active
cast call $POIDH_CONTRACT_ADDRESS \
"bountyCurrentVotingClaim(uint256)(uint256)" \
<BOUNTY_ID> \
--rpc-url $RPC_URL
A return value of 0 indicates there is no current voting claim.
Verify Claimant Is Not Issuer
Resolve signing wallet:
cast wallet address --private-key $PRIVATE_KEY
Compare against:
bounty.issuer
The issuer cannot submit a claim on their own bounty.
Submit Claim
cast send $POIDH_CONTRACT_ADDRESS \
"createClaim(uint256,string,string,string)" \
<BOUNTY_ID> \
"<CLAIM_NAME>" \
"<CLAIM_DESCRIPTION>" \
"<PROOF_URI>" \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
Parameters:
CLAIM_NAME
Short title for the submission.
CLAIM_DESCRIPTION
Explanation of how the claimant completed the bounty.
PROOF_URI
The URI used by poidh.xyz to resolve the media attached to the claim.
See Media Types Supported by poidh.xyz above before choosing this value.
The contract accepts an arbitrary string, but that does not mean an arbitrary URL will display properly on poidh.xyz.
Normal poidh.xyz uploads
The normal poidh.xyz claim form accepts:
.jpg
.jpeg
.png
.gif
.webp
When using that flow, poidh.xyz:
- uploads the image to IPFS
- builds metadata containing the image URI, title, and description
- uploads the metadata to IPFS
- submits the resulting metadata URI to
createClaim
Use the URI returned by that upload flow.
Do not manually invent an IPFS CID, metadata URI, or gateway URL.
Direct contract submissions
A caller interacting directly with:
createClaim(
uint256 bountyId,
string name,
string description,
string imageUri
)
may provide another URI.
For the current poidh.xyz frontend to display it reliably, use one of these forms:
- a direct image URL returning
Content-Type: image/* - a direct video URL returning
Content-Type: video/* - a direct video URL ending in
.mp4,.mov,.webm, or.ogg - JSON metadata containing an
imagefield whose value points to displayable media
For direct images, prefer:
.jpg
.jpeg
.png
.gif
.webp
Do not use the URI field for generic supporting links.
If completion is demonstrated by a GitHub repository, social post, webpage, transaction, benchmark page, documentation, PDF, or another external resource, put that link in CLAIM_DESCRIPTION and use supported media for PROOF_URI.
Example:
CLAIM_NAME:
Offline Android AI submission
CLAIM_DESCRIPTION:
Built and tested the app on GrapheneOS.
Repository: https://github.com/example/project
Demo notes: https://example.com/results
PROOF_URI:
https://example.com/proof.png
or:
PROOF_URI:
https://example.com/claim-metadata.json
where the metadata contains:
{
"image": "https://example.com/proof.png"
}
🚨 Never invent a URI.
Do not put placeholder text, a local filesystem path, an inaccessible temporary URL, or an arbitrary webpage into
PROOF_URI.Before submitting the transaction, verify that the URI resolves to a supported media form that poidh.xyz can display.
Decode Claim ID
After confirmation:
cast receipt <TX_HASH> \
--rpc-url $RPC_URL \
--json
Decode the ClaimCreated event emitted by the poidh core contract.
Do not infer the claim ID from an unrelated log.
Part 5: Evaluating Claims
Winner selection is a high-integrity operation.
The agent must evaluate all eligible claims, not merely the newest ten.
Workflow:
- identify the correct contract bounty ID
- read the bounty
- enumerate every claim
- obtain the proof URI for every claim
- inspect each submission
- apply the bounty's explicit rules
- recommend a winner
- report uncertainty
- obtain user confirmation
- only then transact
🚨 Never recommend a winner until exhaustive claim enumeration has completed successfully.
Step 1: Read Bounty Rules
cast call $POIDH_CONTRACT_ADDRESS \
"bounties(uint256)(uint256,address,string,string,uint256,address,uint256,uint256)" \
<BOUNTY_ID> \
--rpc-url $RPC_URL
The onchain bounty name and description are the base selection rules.
Additional rules visible through the frontend or supplied by the user may also matter if they can be verified.
Step 2: Enumerate Every Claim
Never Page getClaimsByBountyId
This is not an exhaustive data source:
cast call $POIDH_CONTRACT_ADDRESS \
"getClaimsByBountyId(uint256,uint256)(tuple(uint256,address,uint256,address,string,string,uint256,bool)[])" \
<BOUNTY_ID> 0 \
--rpc-url $RPC_URL
It may show recent claims for convenience.
It must never be used as the sole candidate set for winner selection.
Preferred Method: Walk bountyClaims
Enumerate the bounty's exact claim index:
bountyClaims(uint256 bountyId, uint256 index) returns (uint256 claimId)
Read indexes starting at 0 and increasing by one.
For each returned claim ID, read current state with:
cast call $POIDH_CONTRACT_ADDRESS \
"claims(uint256)(uint256,address,uint256,address,string,string,uint256,bool)" \
<CLAIM_ID> \
--rpc-url $RPC_URL
A failed bountyClaims(bountyId, i) call is not by itself proof that index i is out of
bounds. RPC failures and genuine contract reverts may be indistinguishable through some
client libraries.
Before declaring the array complete:
- retry the same exact
bountyClaims(bountyId, i)through a genuinely independent RPC provider - verify that provider is healthy with a known-good contract read
- if the second provider returns a claim ID, continue enumeration
- only accept the boundary if the healthy second provider also reports that exact index unavailable
- if an independent provider is unavailable or health cannot be verified, stop and report that exhaustive enumeration could not be confirmed
Do not replace this with a same-provider canary alone. A provider can successfully answer
one key while failing a different (bountyId, index) read.
This is the preferred authoritative method for enumerating every claim on a specific bounty.
Do not stop after ten results, and do not silently convert an RPC failure into a shorter claim list.
Alternative: ClaimCreated Events
The event is:
event ClaimCreated(
uint256 indexed id,
address indexed issuer,
uint256 indexed bountyId,
address bountyIssuer,
string title,
string description,
uint256 createdAt,
string imageUri,
uint256 round
);
bountyId is indexed, so ClaimCreated logs can be filtered for the target bounty.
Events are useful for:
- alternative exhaustive claim discovery
- retrieving the original proof URI (
imageUri) - claim creation metadata
- historical transaction context
Despite its historical name, imageUri may contain proof that is not an image.
RPC providers may restrict:
- block ranges
- returned log counts
- large
eth_getLogsrequests
If a log query fails, reduce the block range or use the public bountyClaims index.
Do not treat an RPC error as evidence that no claims exist.
Last-Resort Fallback: Global Claim Registry
If targeted index reads and event queries are unavailable, get:
cast call $POIDH_CONTRACT_ADDRESS \
"claimCounter()(uint256)" \
--rpc-url $RPC_URL
Then inspect:
cast call $POIDH_CONTRACT_ADDRESS \
"claims(uint256)(uint256,address,uint256,address,string,string,uint256,bool)" \
<CLAIM_ID> \
--rpc-url $RPC_URL
Retain every claim where:
claim.bountyId == target_bounty_id
Do not stop after ten results.
Batch RPC calls where appropriate.
Step 3: Verify Current Claim State
Claims discovered through events should be checked against current contract state when their current state matters. Claims read through bountyClaims(...) + claims(id) already use current contract state.
cast call $POIDH_CONTRACT_ADDRESS \
"claims(uint256)(uint256,address,uint256,address,string,string,uint256,bool)" \
<CLAIM_ID> \
--rpc-url $RPC_URL
Confirm:
- correct bounty
- correct claimant
- accepted state
- other relevant current state
Step 4: Obtain Proof URI
When ClaimCreated data is available, use:
imageUri
as the submitted proof URI.
If the proof URI was not retrieved during enumeration, query the relevant ClaimCreated event or the NFT contract.
Resolve NFT contract:
NFT_ADDRESS=$(cast call $POIDH_CONTRACT_ADDRESS \
"poidhNft()(address)" \
--rpc-url $RPC_URL)
Then:
cast call $NFT_ADDRESS \
"tokenURI(uint256)(string)" \
<CLAIM_ID> \
--rpc-url $RPC_URL
Step 5: Validate and Resolve the Proof URI
Before evaluating a claim, distinguish between:
claim.description
and:
proof URI / imageUri
The description may contain arbitrary supporting links and explanatory text.
The proof URI is the value poidh.xyz uses to resolve the claim's display media.
The Solidity/event field is historically named imageUri, but supported media is not limited to images.
Do not assume:
- every claim URI uses IPFS
- every URL in the claim description is the claim URI
- a GitHub, social, benchmark, PDF, document, or webpage link belongs in the URI field
- every contract-valid URI is displayable by poidh.xyz
imageUrimust literally point directly to an image file
Current frontend resolution behavior
The current poidh.xyz frontend can resolve:
- direct responses with
Content-Type: image/* - direct responses with
Content-Type: video/* - URLs ending in
.mp4,.mov,.webm, or.ogg - JSON containing an
imagefield - poidh's normal IPFS-hosted claim metadata flow
The native poidh.xyz uploader accepts:
.jpg
.jpeg
.png
.gif
.webp
When validating a direct contract submission, prefer these known-supported forms.
Resolve the URI
The URI may be an IPFS gateway URL, another HTTP(S) URL, or another retrievable URI used by existing poidh claim metadata.
If an ipfs:// URI is encountered, it may be resolved through an IPFS gateway for inspection:
uri = "<URI>"
if uri.startswith("ipfs://"):
url = uri.replace(
"ipfs://",
"https://ipfs.io/ipfs/",
1
)
else:
url = uri
Then inspect the response.
Conceptually:
import requests
response = requests.get(url, timeout=30)
content_type = response.headers.get("content-type", "").lower()
if content_type.startswith("image/"):
content_url = url
media_type = "image"
elif content_type.startswith("video/"):
content_url = url
media_type = "video"
elif url.lower().split("?", 1)[0].endswith(
(".mp4", ".mov", ".webm", ".ogg")
):
content_url = url
media_type = "video"
else:
text = response.text
try:
meta = response.json()
except Exception:
meta = None
if isinstance(meta, dict) and meta.get("image"):
content_url = meta["image"]
media_type = "metadata"
else:
content_url = None
media_type = None
If JSON metadata contains:
{
"image": "<MEDIA_URL>"
}
resolve and inspect that media URL as well.
Do not automatically treat an arbitrary successful HTTP response as valid claim media.
A 200 OK response from a GitHub page, social post, PDF, documentation page, or ordinary HTML webpage does not mean poidh.xyz can display it as claim media.
If the URI cannot be resolved to a supported media form, report the claim media as invalid or inaccessible.
Do not assume:
- every URI is JSON metadata
- every proof URI is an image
- every claim uses IPFS
- PDFs or generic documents are supported claim media
Step 6: Inspect Proof
Use the appropriate capability.
Image
Inspect visually.
Webpage / social post
Open and read it when it is supplied as supporting evidence in the claim description or otherwise referenced by the bounty/submission.
Do not infer that a webpage or social-post URL is a valid claim media URI merely because it is useful evidence.
GitHub repository / PR
Inspect:
- code
- changes
- documentation
- tests
- deliverables
- reproducibility
Video
Inspect available:
- video content
- representative frames
- transcript
- metadata
- linked evidence
PDF / document
Read the document when it is linked as supporting evidence in the claim description or bounty rules.
Do not assume a PDF/document URL is a supported PROOF_URI for frontend display.
Benchmark or dataset
Inspect:
- reported result
- methodology
- traces
- output
- configuration
- reproducibility requirements
Do not reject a claim solely because it is not photographic proof.
Step 7: Apply the Actual Bounty Rules
Possible criteria include:
- eligibility
- completeness
- relevance
- quality
- authenticity
- originality
- reproducibility
- benchmark performance
- deadline
- submission order
- required social post
- required tags
- required links
- creativity
- issuer discretion
Only apply criteria that are present or reasonably implied by the actual bounty.
Do not invent additional requirements.
Earliest-Valid Submission Rules
If the bounty states:
first valid submission wins
or similar language such as:
priority will be given to the earliest valid submission
then claim chronology matters.
Exhaustively enumerate claims and sort qualifying submissions using:
createdAt- claim ID / event order where useful as a secondary ordering signal
Never judge an earliest-valid bounty from only the newest 10 claims.
Step 8: Present Evaluation
Before transacting, report:
- total claims discovered
- enumeration method
- claims evaluated
- inaccessible claims, if any
- disqualified claims and reasons
- qualifying finalists
- recommended winner
- reasoning
- whether chronology affected the decision
- uncertainty
If even one potentially eligible claim cannot be inspected, disclose that.
Do not silently discard inaccessible evidence.
Part 6: Accepting a Solo Bounty Claim
For solo bounties — and open bounties where no external contributor ever participated — acceptance can occur directly.
First check:
cast call $POIDH_CONTRACT_ADDRESS \
"everHadExternalContributor(uint256)(bool)" \
<BOUNTY_ID> \
--rpc-url $RPC_URL
If false, direct acceptance may be used.
Before sending:
- verify bounty is active
- verify selected claim belongs to bounty
- verify all claims were enumerated
- verify winner satisfies bounty rules
- verify signing wallet is issuer
- obtain explicit user confirmation
Then:
cast send $POIDH_CONTRACT_ADDRESS \
"acceptClaim(uint256,uint256)" \
<BOUNTY_ID> \
<CLAIM_ID> \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
Acceptance:
- finalizes the bounty
- credits claimant payout to
pendingWithdrawals - deducts protocol fee
- transfers the winning claim NFT to the issuer
Part 7: Open Bounty Voting
If:
cast call $POIDH_CONTRACT_ADDRESS \
"everHadExternalContributor(uint256)(bool)" \
<BOUNTY_ID> \
--rpc-url $RPC_URL
returns:
true
use contributor voting.
Nominate Claim
Issuer:
cast send $POIDH_CONTRACT_ADDRESS \
"submitClaimForVote(uint256,uint256)" \
<BOUNTY_ID> \
<CLAIM_ID> \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
The issuer's contribution weight is automatically cast as a YES vote.
Contributors then have 2 days to vote YES or NO.
Read Vote Status
cast call $POIDH_CONTRACT_ADDRESS \
"bountyVotingTracker(uint256)(uint256,uint256,uint256)" \
<BOUNTY_ID> \
--rpc-url $RPC_URL
Returns:
yes_weight
no_weight
deadline_timestamp
Resolve Vote
After the deadline:
cast send $POIDH_CONTRACT_ADDRESS \
"resolveVote(uint256)" \
<BOUNTY_ID> \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
Resolution is permissionless.
Part 8: Withdrawing Funds
Winning bounty payouts are credited to:
pendingWithdrawals(address)
Check Balance
cast call $POIDH_CONTRACT_ADDRESS \
"pendingWithdrawals(address)(uint256)" \
<ADDRESS> \
--rpc-url $RPC_URL
Withdraw to Signing Wallet
cast send $POIDH_CONTRACT_ADDRESS \
"withdraw()" \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
Withdraw to Another Address
cast send $POIDH_CONTRACT_ADDRESS \
"withdrawTo(address)" \
<RECIPIENT_ADDRESS> \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
Check the pending balance before sending.
Complete Protocol Enumeration
For analytics or exhaustive historical work, do not rely on the broken convenience getters.
Bounties
cast call $POIDH_CONTRACT_ADDRESS \
"bountyCounter()(uint256)" \
--rpc-url $RPC_URL
Then:
cast call $POIDH_CONTRACT_ADDRESS \
"bounties(uint256)(uint256,address,string,string,uint256,address,uint256,uint256)" \
<ID> \
--rpc-url $RPC_URL
Claims
cast call $POIDH_CONTRACT_ADDRESS \
"claimCounter()(uint256)" \
--rpc-url $RPC_URL
Then:
cast call $POIDH_CONTRACT_ADDRESS \
"claims(uint256)(uint256,address,uint256,address,string,string,uint256,bool)" \
<ID> \
--rpc-url $RPC_URL
For large scans, use batched JSON-RPC requests.
For ordinary application development, consider the poidh indexer instead.
Broken Getter Technical Reference
The known faulty pattern is equivalent to:
uint256 counter;
for (
uint256 i = ids.length;
i > offset && counter < 10;
i--
) {
result[counter] = items[ids[i - 1]];
counter++;
}
The loop always starts at:
ids.length
not:
ids.length - offset
Therefore offset acts as a lower loop boundary rather than a page starting position.
For collections containing more than ten entries, the loop typically reaches:
counter == 10
before the offset changes the returned records.
A large offset near the array length may shorten the returned result, creating the misleading appearance that offset is working.
A proper conceptual newest-first implementation would instead resemble:
if (offset >= ids.length) {
return new Claim[](0);
}
for (
uint256 i = ids.length - offset;
i > 0 && counter < 10;
i--
) {
result[counter] = claims[ids[i - 1]];
counter++;
}
The deployed contracts are immutable.
Do not assume this bug will change at the existing addresses.
Native Token Reference
poidh uses ETH on every network supported by this skill.
| Human amount | Cast value |
|---|---|
0.001 ETH | 0.001ether |
0.01 ETH | 0.01ether |
0.1 ETH | 0.1ether |
1 ETH | 1ether |
Protocol Fee
PoidhV3 takes a 2.5% protocol fee on accepted bounty payouts.
The fee is applied at settlement.
Before settlement, contributed funds remain in bounty escrow subject to the contract's rules.
The winner receives the bounty payout minus the protocol fee through the withdrawal mechanism.
Agent Decision Flow
Discovering a Bounty
-
Use:
https://poidh.xyz/bounties/data, or- the poidh indexer.
-
Filter opportunities according to the user's request.
-
Inspect the individual bounty
/dataendpoint for:- bounty description
- amount
- chain
- status
- issuer
- claims
- comments
-
Always inspect public comments for clarifications, requirement changes, answers from the bounty creator, or other context that may affect how the bounty should be completed.
-
Before submitting a claim or performing another transaction, verify current critical state directly onchain.
Posting a Bounty
-
Determine:
- chain
- name
- description
- ETH amount
- solo/open
-
Resolve v3 contract.
-
Verify
MIN_BOUNTY_AMOUNT(). -
Verify wallet is an EOA.
-
Verify sufficient ETH.
-
Explain transaction.
-
Obtain confirmation.
-
Send transaction.
-
Decode creation event.
-
Return:
- transaction hash
- contract bounty ID
- frontend URL
Submitting a Claim
-
Determine:
- chain
- bounty
- claim name
- claim description
- proof URI
-
If given frontend URL:
- use
/data - obtain
onChainId
- use
-
Verify bounty onchain.
-
Verify no active vote.
-
Verify wallet is not issuer.
-
Explain transaction.
-
Obtain confirmation.
-
Submit claim.
-
Decode
ClaimCreated. -
Return claim ID and transaction hash.
Evaluating a Bounty
- Resolve contract bounty ID.
- Read bounty rules.
- Enumerate every claim.
- Prefer
bountyClaims(bountyId, i)walked from0upward. - If an indexed read fails, confirm the same exact index through a healthy independent RPC provider before treating it as the array boundary.
- If no independent provider is available, do not claim exhaustive enumeration succeeded.
- Read each returned claim ID with
claims(id). - Use
ClaimCreatedlogs to retrieve proof URIs or as an alternative exhaustive discovery path. - Fall back to
claimCounter()+claims(id)only when necessary. - Never use paginated
getClaimsByBountyIdas the complete candidate list. - Resolve every proof URI.
- Inspect every potentially eligible submission.
- Apply only the bounty's actual requirements.
- Account for deadlines and chronology.
- Present findings.
- Obtain user confirmation before accepting or nominating.
Accepting a Claim
-
Verify all claims were evaluated.
-
Verify selected claim.
-
Check external-contributor state.
-
If no external contributor:
acceptClaim
-
If external contributors exist:
submitClaimForVote
-
Explain result to user.
Transaction Safety Rules
Before every write transaction:
- verify network
- verify v3 contract address
- verify bounty ID
- verify claim ID if applicable
- verify frontend ID conversion if applicable
- verify current onchain state
- verify signing wallet
- verify ETH amount
- explain the exact effect of the transaction
- obtain explicit user confirmation
Never send funds to an unverified contract address.
Never interact with a poidh v2 contract.
Never expose the private key.
Never execute a winner transaction solely because an automated evaluation produced a recommendation.
Evaluation and transaction execution are separate actions.
Error Reference
| Error | Cause | Fix |
|---|---|---|
ContractsCannotCreateBounties() | Wallet is a smart contract | Use an EOA |
MinimumBountyNotMet() | Bounty below minimum | Increase --value |
MinimumContributionNotMet() | Contribution below minimum | Increase contribution |
NoEther() | No ETH sent | Add --value |
WrongCaller() | Caller not authorized | Use issuer wallet |
VotingOngoing() | Vote active | Wait or resolve after deadline |
VotingEnded() | Voting window finished | Resolve vote |
NotSoloBounty() | Direct acceptance unavailable | Use voting flow |
ClaimAlreadyAccepted() | Claim already accepted | No further action |
BountyClaimed() | Bounty finalized | No further action |
BountyClosed() | Bounty cancelled | No further action |
BountyNotFound() | Wrong contract bounty ID | Verify ID |
ClaimNotFound() | Invalid claim ID | Verify claim |
IssuerCannotClaim() | Issuer attempted own bounty | Use different claimant wallet |
NotActiveParticipant() | Caller not active contributor | Verify contribution state |
MaxParticipantsReached() | Contributor cap reached | Cannot join until slot becomes available |
NothingToWithdraw() | No pending payout | Check pending balance |
VoteWouldPass() | Attempted invalid vote reset | Cannot override passing vote that way |
Critical Rules
- Only interact with poidh v3 contracts.
- Never interact with poidh v2 contracts.
- Only use Ethereum Mainnet, Arbitrum, or Base for live poidh activity.
- Degen Chain (
666666666) is retired. Treat Degen records as historical and never attempt transactions or wallet switching on Degen. - Never treat a historical Degen bounty as actionable merely because frontend or indexer data reports it as open.
- Treat poidh's deployed contracts as immutable.
- Never trust the four broken
offsetgetters for exhaustive enumeration. - Never evaluate only the newest 10 claims when choosing a winner.
- Never treat a failed
bountyClaims,userClaims, oruserBountiesindexed read as proof that the array ended without confirming the same exact index through a healthy independent RPC provider. - If independent boundary confirmation is unavailable, fail loudly and do not claim exhaustive enumeration succeeded.
- Use
bountyClaims(bountyId, i)+claims(id)as the preferred exhaustive claim-enumeration path. UseClaimCreatedlogs as an alternative and for proof URI retrieval. - Use
/bounties/data, individual/dataendpoints, or the indexer for convenient discovery. - Treat indexer and frontend JSON data as derived convenience data, not final consensus state.
- Verify critical state directly onchain before any transaction.
- Always distinguish frontend bounty IDs from v3 contract bounty IDs.
- Prefer
onChainIdfrom the individual JSON endpoint when available. - Respect rules such as "first valid submission wins."
- Never silently ignore an inaccessible claim.
- Confirm with the user before every state-changing transaction.
- Never reveal or log the user's private key.
- Treat the claim URI as the value poidh.xyz uses to resolve claim display media, not as a generic evidence-link field.
- The native poidh.xyz claim uploader accepts
.jpg,.jpeg,.png,.gif, and.webp, uploads the image to IPFS, then submits IPFS-hosted metadata containing the image URI. - For direct contract submissions, use media the current frontend can resolve:
image/*,video/*,.mp4,.mov,.webm,.ogg, or JSON metadata containing animagefield. - Do not assume arbitrary PDFs, documents, GitHub pages, social posts, ordinary webpages, benchmark pages, or other generic URLs will display as claim media. Put those links in the claim description.
- Contract-valid is not the same thing as frontend-displayable. Verify the URI resolves to supported media before creating a claim.
- Never invent, guess, or submit a placeholder proof URI.
レビュー
まだレビューはありません。使ってみた感想をお寄せください。
コメント
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。