本文へ移動
cccskills
無料GitHub で公開

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.

日本語の概要は準備中です。原文の説明を表示しています。

picsoritdidnthappen/poidh-appスター 39(GitHub 39 + cccskills 0)
連携ツールX (Twitter)

実行スコア 未検証

インストール方法を見る

含まれるファイル(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:

  1. Discover bounties
  2. Read bounty and claim data
  3. Post bounties — solo or open
  4. Submit claims
  5. Evaluate claim submissions
  6. Accept winning claims on solo bounties
  7. Initiate and resolve contributor voting on open bounties
  8. 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.

ToolDoes
find_bountiesList open bounties, or search all bounties by text
get_bountyComplete bounty data: status, all claims, comments, winner, voting state and identities
get_accountComplete public profile/activity data: bounties, claims, NFTs, comments, score and related users
get_leaderboardLeaderboard by points
prepare_create_bountyUnsigned tx: post a solo or open bounty
prepare_join_bountyUnsigned tx: add funds to an open bounty
prepare_submit_claimUnsigned tx: submit a claim (see the URI rules below)
prepare_accept_claimUnsigned tx: accept a claim, or start a vote when contributors exist
prepare_voteUnsigned tx: vote on the claim under vote
prepare_resolve_voteUnsigned tx: resolve a finished vote
prepare_withdrawUnsigned tx: withdraw winnings

The MCP server never signs or holds keys. prepare_* tools return:

  • transaction: { chainId, to, data, value } for eth_sendTransaction
  • walletSendCalls: the same call as an EIP-5792 wallet_sendCalls request
  • simulation: an eth_call dry run when you pass from, with decoded contract errors
  • signUrl: a https://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 /data endpoints

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 /data endpoints
  • 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:

  1. a name
  2. a description
  3. 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:

  1. uploads the image file to IPFS
  2. creates metadata containing the uploaded image URI
  3. uploads that metadata to IPFS
  4. 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:

  1. choose a real, accessible URI
  2. verify that it resolves to supported media or supported JSON metadata
  3. verify that poidh.xyz can display the resulting claim media
  4. 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:

  1. integrations do not need to account for proxy upgrades or implementation changes at these addresses
  2. 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

ChainCore ContractExplorer
Ethereum Mainnet0xE731dFadBFf20542E10D09D26Fc71445C70d4232https://etherscan.io/address/0xe731dfadbff20542e10d09d26fc71445c70d4232
Arbitrum0x5555Fa783936C260f77385b4E153B9725feF1719https://arbiscan.io/address/0x5555fa783936c260f77385b4E153B9725fef1719
Base0x5555Fa783936C260f77385b4E153B9725feF1719https://basescan.org/address/0x5555fa783936c260f77385b4E153B9725fef1719

poidh v3 NFT Contracts

Claim proof NFTs are minted through the poidh NFT contracts.

ChainNFT Contract
Ethereum Mainnet0x9c5f45d5e1382e4058d334d93c6c01442012a4d9
Arbitrum0x27e117cc9a8da363442e7bd0618939e3eeeacf6a
Base0x27e117cc9a8da363442e7bd0618939e3eeeacf6a

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:

  1. read bountyClaims(bountyId, i) from the current provider
  2. if it returns a claim ID, record it and continue
  3. if it fails, retry the same exact (bountyId, i) read through a genuinely independent RPC provider
  4. verify the second provider is healthy with at least one known-good read
  5. if the independent provider returns a claim ID, the first provider failed; continue the walk
  6. only treat index i as the end when a healthy independent provider also reports that the same index is unavailable
  7. 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 useExact 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 bounty
  • userBounties(user, i) for bounties associated with one user
  • userClaims(user, i) for claims associated with one user
  • bountyCounter() + bounties(id) for the complete bounty registry
  • claimCounter() + 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 terminology
  • githubUrl — 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

VariableDescription
PRIVATE_KEYPrivate key of the EOA signing transactions, hex with or without 0x
RPC_URLRPC URL for the target chain
POIDH_CHAINmainnet, 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:

ChainOffset
Ethereum Mainnet0
Arbitrum180
Base986

Example:

Base contract bounty ID: 285

285 + 986 = 1271

Frontend:
https://poidh.xyz/base/bounty/1271

🚨 Never assume /base/bounty/106 corresponds to bounties(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 onChainId to 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, including claimId, the raw claim uri, claimant address, resolved name, Farcaster handle, Twitter handle, poidh profile URL, title, and description.

    uri is 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:

  1. uploads the image to IPFS
  2. builds metadata containing the image URI, title, and description
  3. uploads the metadata to IPFS
  4. 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 image field 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:

  1. identify the correct contract bounty ID
  2. read the bounty
  3. enumerate every claim
  4. obtain the proof URI for every claim
  5. inspect each submission
  6. apply the bounty's explicit rules
  7. recommend a winner
  8. report uncertainty
  9. obtain user confirmation
  10. 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:

  1. retry the same exact bountyClaims(bountyId, i) through a genuinely independent RPC provider
  2. verify that provider is healthy with a known-good contract read
  3. if the second provider returns a claim ID, continue enumeration
  4. only accept the boundary if the healthy second provider also reports that exact index unavailable
  5. 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_getLogs requests

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
  • imageUri must literally point directly to an image file

Current frontend resolution behavior

The current poidh.xyz frontend can resolve:

  1. direct responses with Content-Type: image/*
  2. direct responses with Content-Type: video/*
  3. URLs ending in .mp4, .mov, .webm, or .ogg
  4. JSON containing an image field
  5. 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:

  1. verify bounty is active
  2. verify selected claim belongs to bounty
  3. verify all claims were enumerated
  4. verify winner satisfies bounty rules
  5. verify signing wallet is issuer
  6. 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 amountCast value
0.001 ETH0.001ether
0.01 ETH0.01ether
0.1 ETH0.1ether
1 ETH1ether

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

  1. Use:

    • https://poidh.xyz/bounties/data, or
    • the poidh indexer.
  2. Filter opportunities according to the user's request.

  3. Inspect the individual bounty /data endpoint for:

    • bounty description
    • amount
    • chain
    • status
    • issuer
    • claims
    • comments
  4. 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.

  5. Before submitting a claim or performing another transaction, verify current critical state directly onchain.


Posting a Bounty

  1. Determine:

    • chain
    • name
    • description
    • ETH amount
    • solo/open
  2. Resolve v3 contract.

  3. Verify MIN_BOUNTY_AMOUNT().

  4. Verify wallet is an EOA.

  5. Verify sufficient ETH.

  6. Explain transaction.

  7. Obtain confirmation.

  8. Send transaction.

  9. Decode creation event.

  10. Return:

    • transaction hash
    • contract bounty ID
    • frontend URL

Submitting a Claim

  1. Determine:

    • chain
    • bounty
    • claim name
    • claim description
    • proof URI
  2. If given frontend URL:

    • use /data
    • obtain onChainId
  3. Verify bounty onchain.

  4. Verify no active vote.

  5. Verify wallet is not issuer.

  6. Explain transaction.

  7. Obtain confirmation.

  8. Submit claim.

  9. Decode ClaimCreated.

  10. Return claim ID and transaction hash.


Evaluating a Bounty

  1. Resolve contract bounty ID.
  2. Read bounty rules.
  3. Enumerate every claim.
  4. Prefer bountyClaims(bountyId, i) walked from 0 upward.
  5. If an indexed read fails, confirm the same exact index through a healthy independent RPC provider before treating it as the array boundary.
  6. If no independent provider is available, do not claim exhaustive enumeration succeeded.
  7. Read each returned claim ID with claims(id).
  8. Use ClaimCreated logs to retrieve proof URIs or as an alternative exhaustive discovery path.
  9. Fall back to claimCounter() + claims(id) only when necessary.
  10. Never use paginated getClaimsByBountyId as the complete candidate list.
  11. Resolve every proof URI.
  12. Inspect every potentially eligible submission.
  13. Apply only the bounty's actual requirements.
  14. Account for deadlines and chronology.
  15. Present findings.
  16. Obtain user confirmation before accepting or nominating.

Accepting a Claim

  1. Verify all claims were evaluated.

  2. Verify selected claim.

  3. Check external-contributor state.

  4. If no external contributor:

    • acceptClaim
  5. If external contributors exist:

    • submitClaimForVote
  6. Explain result to user.


Transaction Safety Rules

Before every write transaction:

  1. verify network
  2. verify v3 contract address
  3. verify bounty ID
  4. verify claim ID if applicable
  5. verify frontend ID conversion if applicable
  6. verify current onchain state
  7. verify signing wallet
  8. verify ETH amount
  9. explain the exact effect of the transaction
  10. 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

ErrorCauseFix
ContractsCannotCreateBounties()Wallet is a smart contractUse an EOA
MinimumBountyNotMet()Bounty below minimumIncrease --value
MinimumContributionNotMet()Contribution below minimumIncrease contribution
NoEther()No ETH sentAdd --value
WrongCaller()Caller not authorizedUse issuer wallet
VotingOngoing()Vote activeWait or resolve after deadline
VotingEnded()Voting window finishedResolve vote
NotSoloBounty()Direct acceptance unavailableUse voting flow
ClaimAlreadyAccepted()Claim already acceptedNo further action
BountyClaimed()Bounty finalizedNo further action
BountyClosed()Bounty cancelledNo further action
BountyNotFound()Wrong contract bounty IDVerify ID
ClaimNotFound()Invalid claim IDVerify claim
IssuerCannotClaim()Issuer attempted own bountyUse different claimant wallet
NotActiveParticipant()Caller not active contributorVerify contribution state
MaxParticipantsReached()Contributor cap reachedCannot join until slot becomes available
NothingToWithdraw()No pending payoutCheck pending balance
VoteWouldPass()Attempted invalid vote resetCannot override passing vote that way

Critical Rules

  1. Only interact with poidh v3 contracts.
  2. Never interact with poidh v2 contracts.
  3. Only use Ethereum Mainnet, Arbitrum, or Base for live poidh activity.
  4. Degen Chain (666666666) is retired. Treat Degen records as historical and never attempt transactions or wallet switching on Degen.
  5. Never treat a historical Degen bounty as actionable merely because frontend or indexer data reports it as open.
  6. Treat poidh's deployed contracts as immutable.
  7. Never trust the four broken offset getters for exhaustive enumeration.
  8. Never evaluate only the newest 10 claims when choosing a winner.
  9. Never treat a failed bountyClaims, userClaims, or userBounties indexed read as proof that the array ended without confirming the same exact index through a healthy independent RPC provider.
  10. If independent boundary confirmation is unavailable, fail loudly and do not claim exhaustive enumeration succeeded.
  11. Use bountyClaims(bountyId, i) + claims(id) as the preferred exhaustive claim-enumeration path. Use ClaimCreated logs as an alternative and for proof URI retrieval.
  12. Use /bounties/data, individual /data endpoints, or the indexer for convenient discovery.
  13. Treat indexer and frontend JSON data as derived convenience data, not final consensus state.
  14. Verify critical state directly onchain before any transaction.
  15. Always distinguish frontend bounty IDs from v3 contract bounty IDs.
  16. Prefer onChainId from the individual JSON endpoint when available.
  17. Respect rules such as "first valid submission wins."
  18. Never silently ignore an inaccessible claim.
  19. Confirm with the user before every state-changing transaction.
  20. Never reveal or log the user's private key.
  21. Treat the claim URI as the value poidh.xyz uses to resolve claim display media, not as a generic evidence-link field.
  22. 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.
  23. For direct contract submissions, use media the current frontend can resolve: image/*, video/*, .mp4, .mov, .webm, .ogg, or JSON metadata containing an image field.
  24. 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.
  25. Contract-valid is not the same thing as frontend-displayable. Verify the URI resolves to supported media before creating a claim.
  26. Never invent, guess, or submit a placeholder proof URI.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

このスキルの問題を報告する