{
  "schemaVersion": "1.0",
  "item": {
    "slug": "poidh",
    "name": "POIDH Bounty Bot",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/saltoriousSIG/poidh",
    "canonicalUrl": "https://clawhub.ai/saltoriousSIG/poidh",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/poidh",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=poidh",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/poidh"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/poidh",
    "agentPageUrl": "https://openagent3.xyz/skills/poidh/agent",
    "manifestUrl": "https://openagent3.xyz/skills/poidh/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/poidh/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Overview",
        "body": "This skill interacts with the PoidhV3 contracts on Arbitrum, Base, and Degen Chain to:\n\nPost bounties (solo or open)\nEvaluate claim submissions using vision — fetch the image URI from each claim and compare against the bounty description\nAccept the winning claim (solo bounty) or initiate + resolve a vote (open bounty)\n\npoidh (\"pics or it didn't happen\") is a fully on-chain bounty protocol. Claimants submit photo proof, and the bounty issuer (or contributors via vote) accepts the best claim to release funds.\n\n⚠️ The PoidhV3 contract enforces msg.sender == tx.origin. Only EOA wallets can create or accept bounties. Smart contract wallets (Safe, etc.) will revert with ContractsCannotCreateBounties."
      },
      {
        "title": "Required Environment Variables",
        "body": "VariableDescriptionPRIVATE_KEYPrivate key of the EOA signing transactions (hex, with or without 0x prefix)RPC_URLRPC URL for the target chainPOIDH_CHAINTarget chain: arbitrum, base, or degen\n\nPOIDH_CONTRACT_ADDRESS is resolved automatically from POIDH_CHAIN — do not set it manually."
      },
      {
        "title": "Supported Chains",
        "body": "ChainContract AddressExplorerArbitrum0x5555Fa783936C260f77385b4E153B9725feF1719arbiscan.ioBase0x5555Fa783936C260f77385b4E153B9725feF1719basescan.orgDegen Chain0x18E5585ca7cE31b90Bc8BB7aAf84152857cE243fexplorer.degen.tips\n\n⚠️ Minimum amounts differ by chain. On Arbitrum and Base: 0.001 ETH minimum bounty, 0.00001 ETH minimum contribution. On Degen Chain: 1000 DEGEN minimum bounty, 10 DEGEN minimum contribution. Always verify on-chain before posting:\ncast call $POIDH_CONTRACT_ADDRESS \"MIN_BOUNTY_AMOUNT()(uint256)\" --rpc-url $RPC_URL\ncast call $POIDH_CONTRACT_ADDRESS \"MIN_CONTRIBUTION()(uint256)\" --rpc-url $RPC_URL\n\nResolve the contract address at the start of every session:\n\nif [ \"$POIDH_CHAIN\" = \"degen\" ]; then\n  POIDH_CONTRACT_ADDRESS=\"0x18E5585ca7cE31b90Bc8BB7aAf84152857cE243f\"\nelse\n  # arbitrum and base share the same address\n  POIDH_CONTRACT_ADDRESS=\"0x5555Fa783936C260f77385b4E153B9725feF1719\"\nfi\n\nThe poidh.xyz URL also changes per chain:\n\nif [ \"$POIDH_CHAIN\" = \"arbitrum\" ]; then\n  POIDH_BASE_URL=\"https://poidh.xyz/arbitrum\"\n  POIDH_V2_OFFSET=180\nelif [ \"$POIDH_CHAIN\" = \"degen\" ]; then\n  POIDH_BASE_URL=\"https://poidh.xyz/degen\"\n  POIDH_V2_OFFSET=1197\nelse\n  POIDH_BASE_URL=\"https://poidh.xyz/base\"\n  POIDH_V2_OFFSET=986\nfi"
      },
      {
        "title": "Check Minimum Bounty Amount",
        "body": "cast call $POIDH_CONTRACT_ADDRESS \"MIN_BOUNTY_AMOUNT()(uint256)\" --rpc-url $RPC_URL"
      },
      {
        "title": "Post a Solo Bounty",
        "body": "Solo = only you fund it; you accept claims directly with no vote required.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"createSoloBounty(string,string)\" \\\n  \"<BOUNTY_NAME>\" \\\n  \"<BOUNTY_DESCRIPTION>\" \\\n  --value <AMOUNT> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nExample:\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"createSoloBounty(string,string)\" \\\n  \"Brooklyn Bridge at sunset\" \\\n  \"High quality photo of the Brooklyn Bridge during golden hour. Must show the full span.\" \\\n  --value 0.001ether \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL"
      },
      {
        "title": "Post an Open Bounty",
        "body": "Open = others can co-fund; claim acceptance requires a contributor-weighted vote.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"createOpenBounty(string,string)\" \\\n  \"<BOUNTY_NAME>\" \\\n  \"<BOUNTY_DESCRIPTION>\" \\\n  --value <AMOUNT> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL"
      },
      {
        "title": "Get the Bounty ID After Posting",
        "body": "cast receipt <TX_HASH> --rpc-url $RPC_URL --json | \\\n  python3 -c \"\nimport sys, json\nreceipt = json.load(sys.stdin)\nfor log in receipt['logs']:\n    if log['address'].lower() == '${POIDH_CONTRACT_ADDRESS}'.lower() and len(log['topics']) >= 2:\n        bounty_id = int(log['topics'][1], 16)\n        frontend_id = bounty_id + ${POIDH_V2_OFFSET}\n        print(f'Bounty ID: {bounty_id}')\n        print(f'View at: ${POIDH_BASE_URL}/bounty/{frontend_id}')\n        break\n\""
      },
      {
        "title": "Part 2: Evaluating Claims",
        "body": "When the user wants to pick a winner, the agent must:\n\nFetch all claims for the bounty\nRetrieve each claim's URI from the NFT contract\nFetch and evaluate the content against the bounty description\nPick the best match\n\nClaim submissions are freeform — the URI could point to an image, a video, a tweet, a GitHub PR, a webpage, a document, or anything else. Evaluate whatever you find against what the bounty asked for."
      },
      {
        "title": "Step 1: Fetch Claims for a Bounty",
        "body": "cast call $POIDH_CONTRACT_ADDRESS \\\n  \"getClaimsByBountyId(uint256,uint256)(tuple(uint256,address,uint256,address,string,string,uint256,bool)[])\" \\\n  <BOUNTY_ID> 0 \\\n  --rpc-url $RPC_URL\n\nReturns up to 10 claims (most recent first). Increment offset by 10 to paginate. Each claim tuple:\n(id, issuer, bountyId, bountyIssuer, name, description, createdAt, accepted)\n\nThe name and description fields on the claim are also set by the claimant and may give useful context about what they submitted."
      },
      {
        "title": "Step 2: Get the URI for Each Claim",
        "body": "# Get NFT contract address\nNFT_ADDRESS=$(cast call $POIDH_CONTRACT_ADDRESS \"poidhNft()(address)\" --rpc-url $RPC_URL)\n\n# Get token URI for a specific claim\ncast call $NFT_ADDRESS \"tokenURI(uint256)(string)\" <CLAIM_ID> --rpc-url $RPC_URL"
      },
      {
        "title": "Step 3: Resolve the URI",
        "body": "Convert non-HTTP URIs to fetchable URLs:\n\nuri = \"<URI_FROM_TOKEN>\"\nif uri.startswith(\"ipfs://\"):\n    url = uri.replace(\"ipfs://\", \"https://ipfs.io/ipfs/\")\nelif uri.startswith(\"ar://\"):\n    url = uri.replace(\"ar://\", \"https://arweave.net/\")\nelse:\n    url = uri  # already HTTP\n\nIf the URL returns JSON metadata (standard ERC721 format), check for an image or animation_url field and resolve those too:\n\nimport requests\n\nresponse = requests.get(url)\ntry:\n    meta = response.json()\n    # Prefer animation_url (video/interactive) over image if both present\n    content_url = meta.get(\"animation_url\") or meta.get(\"image\") or url\n    if content_url.startswith(\"ipfs://\"):\n        content_url = content_url.replace(\"ipfs://\", \"https://ipfs.io/ipfs/\")\nexcept Exception:\n    content_url = url  # URI points directly to the content"
      },
      {
        "title": "Step 4: Evaluate the Content",
        "body": "Fetch and review the content at content_url. Use the appropriate method based on what you find:\n\nImage — use native vision to view it directly\nWebpage / tweet / article — use the web fetch tool to read the content\nVideo — note the URL and evaluate based on the thumbnail or any available metadata\nDocument / PDF — fetch and read the text content\n\nEvaluate each claim against the bounty name and description on:\n\nRelevance — does the submission match what was actually asked for?\nQuality — is it complete, clear, and unambiguous?\nAuthenticity — does it appear genuine and original (not recycled or faked)?\n\nPick the claim with the highest overall score. Present your reasoning to the user before executing any transaction."
      },
      {
        "title": "Part 3: Accepting a Winning Claim — Solo Bounty",
        "body": "For solo bounties (and open bounties where no external contributors ever joined), the issuer accepts directly. This immediately finalizes the bounty, credits the claimant payout to pendingWithdrawals, takes the 2.5% protocol fee, and transfers the claim NFT to the issuer.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"acceptClaim(uint256,uint256)\" \\\n  <BOUNTY_ID> <CLAIM_ID> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL"
      },
      {
        "title": "Part 4: Accepting a Winning Claim — Open Bounty (Vote Flow)",
        "body": "For open bounties where external contributors have joined, direct accept is blocked. Use the two-step vote flow."
      },
      {
        "title": "Check if External Contributors Exist",
        "body": "cast call $POIDH_CONTRACT_ADDRESS \\\n  \"everHadExternalContributor(uint256)(bool)\" \\\n  <BOUNTY_ID> \\\n  --rpc-url $RPC_URL\n\nIf false, fall back to acceptClaim (Part 3). If true, proceed with the vote flow below."
      },
      {
        "title": "Step 1: Submit the Chosen Claim for Vote (Issuer Only)",
        "body": "The issuer's full contribution weight is automatically cast as a YES vote at this point.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"submitClaimForVote(uint256,uint256)\" \\\n  <BOUNTY_ID> <CLAIM_ID> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nAfter this call, other contributors have 2 days to vote YES/NO via the poidh.xyz UI or by calling voteClaim(bountyId, bool) directly."
      },
      {
        "title": "Step 2: Check Vote Status",
        "body": "cast call $POIDH_CONTRACT_ADDRESS \\\n  \"bountyVotingTracker(uint256)(uint256,uint256,uint256)\" \\\n  <BOUNTY_ID> \\\n  --rpc-url $RPC_URL\n# Returns: yes_weight, no_weight, deadline_timestamp\n\npython3 -c \"import time; deadline=<DEADLINE>; print('Voting ended' if time.time() > deadline else f'Voting ends in {int((deadline - time.time())/3600)}h')\""
      },
      {
        "title": "Step 3: Resolve the Vote (Permissionless)",
        "body": "After the 2-day window closes, anyone can resolve. If YES weight > 50% of total weight, the claim is accepted and funds are distributed.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"resolveVote(uint256)\" \\\n  <BOUNTY_ID> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL"
      },
      {
        "title": "Part 5: Submitting a Claim on Someone Else's Bounty",
        "body": "Any EOA (except the bounty issuer) can submit a claim on an active open or solo bounty. This is how the agent acts as a claimant rather than an issuer. No native token is required to submit a claim — only gas.\n\nThe uri is the proof of completion — it can be anything: an IPFS image hash, a direct image URL, a tweet, a GitHub link, a webpage, a video, etc. It gets minted into a claim NFT at submission time."
      },
      {
        "title": "Check That the Bounty is Active",
        "body": "Before submitting, verify the bounty exists, is not finalized, and has no ongoing vote:\n\ncast call $POIDH_CONTRACT_ADDRESS \\\n  \"bounties(uint256)(uint256,address,string,string,uint256,address,uint256,uint256)\" \\\n  <BOUNTY_ID> \\\n  --rpc-url $RPC_URL\n# Returns: id, issuer, name, description, amount, claimer, createdAt, claimId\n# claimer == 0x0 means active; claimer == issuer means cancelled; claimer == other means already won\n\nAlso confirm no vote is currently in progress:\n\ncast call $POIDH_CONTRACT_ADDRESS \\\n  \"bountyCurrentVotingClaim(uint256)(uint256)\" \\\n  <BOUNTY_ID> \\\n  --rpc-url $RPC_URL\n# Returns 0 if no active vote — safe to submit"
      },
      {
        "title": "Submit the Claim",
        "body": "cast send $POIDH_CONTRACT_ADDRESS \\\n  \"createClaim(uint256,string,string,string)\" \\\n  <BOUNTY_ID> \\\n  \"<CLAIM_NAME>\" \\\n  \"<CLAIM_DESCRIPTION>\" \\\n  \"<PROOF_URI>\" \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nCLAIM_NAME — short title for the submission\nCLAIM_DESCRIPTION — explanation of how the bounty was completed\nPROOF_URI — the actual proof (image URL, IPFS URI, tweet URL, GitHub link, etc.)\n\nExample:\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"createClaim(uint256,string,string,string)\" \\\n  42 \\\n  \"Brooklyn Bridge golden hour\" \\\n  \"Took this photo at 7:43pm on the Manhattan side. Full span visible with reflection in the water.\" \\\n  \"ipfs://QmXyz...\" \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL"
      },
      {
        "title": "Get the Claim ID After Submitting",
        "body": "cast receipt <TX_HASH> --rpc-url $RPC_URL --json | \\\n  python3 -c \"\nimport sys, json\nreceipt = json.load(sys.stdin)\nfor log in receipt['logs']:\n    if log['address'].lower() == '$POIDH_CONTRACT_ADDRESS'.lower() and len(log['topics']) >= 2:\n        claim_id = int(log['topics'][1], 16)\n        print(f'Claim ID: {claim_id}')\n        break\n\""
      },
      {
        "title": "Important Constraints",
        "body": "The agent's wallet (PRIVATE_KEY) cannot be the bounty issuer — IssuerCannotClaim will revert\nSubmitting is blocked while a vote is active on that bounty — VotingOngoing will revert\nThe bounty must still be open — finalized or cancelled bounties will revert\nThere is no limit to the number of claims per bounty; the issuer picks the best one"
      },
      {
        "title": "Part 6: Withdrawing Funds",
        "body": "After winning a bounty as claimant, funds are credited to pendingWithdrawals and must be explicitly collected. The bounty payout minus the 2.5% protocol fee is available immediately after acceptClaim or resolveVote finalizes."
      },
      {
        "title": "Check Pending Balance",
        "body": "cast call $POIDH_CONTRACT_ADDRESS \\\n  \"pendingWithdrawals(address)(uint256)\" \\\n  <YOUR_ADDRESS> \\\n  --rpc-url $RPC_URL"
      },
      {
        "title": "Withdraw to Your Own Address",
        "body": "cast send $POIDH_CONTRACT_ADDRESS \\\n  \"withdraw()\" \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL"
      },
      {
        "title": "Withdraw to a Different Address",
        "body": "cast send $POIDH_CONTRACT_ADDRESS \\\n  \"withdrawTo(address)\" \\\n  <RECIPIENT_ADDRESS> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nwithdraw() sends the entire pending balance in one call. Check balance first to confirm funds are available before sending the transaction."
      },
      {
        "title": "Posting a Bounty",
        "body": "Ask for: name, description, amount (ETH on Arbitrum/Base, DEGEN on Degen Chain), type (solo or open — default solo)\nConfirm with user before sending — this spends real ETH (or DEGEN on Degen Chain)\nRun createSoloBounty or createOpenBounty\nReturn tx hash and $POIDH_BASE_URL/bounty/<bountyId + $POIDH_V2_OFFSET>"
      },
      {
        "title": "Submitting a Claim",
        "body": "Ask for: bounty ID, proof URI (image, link, IPFS hash, etc.), claim name, claim description\nVerify the bounty is active and has no ongoing vote\nConfirm the agent's wallet is not the bounty issuer\nConfirm with user before sending\nCall createClaim(bountyId, name, description, uri)\nReturn the claim ID and tx hash"
      },
      {
        "title": "Evaluating and Accepting",
        "body": "Ask for the bounty ID\nCheck everHadExternalContributor to determine the correct acceptance path\nFetch all active (non-accepted) claims via getClaimsByBountyId\nFor each claim: get tokenURI, resolve URI, evaluate content using the appropriate tool (vision for images, web fetch for links, etc.)\nPresent recommended winner + reasoning to user, confirm before transacting\nSolo / no external contributors: acceptClaim(bountyId, claimId)\nOpen with external contributors: submitClaimForVote(bountyId, claimId), inform user contributors have 2 days to vote, then resolveVote after deadline"
      },
      {
        "title": "Native Token Amount Reference",
        "body": "Human amountCast value0.001 ETH0.001ether0.01 ETH0.01ether1 ETH1ether1000 DEGEN1000ether10 DEGEN10ether\n\ncast uses ether as a unit label for any 18-decimal token. On Degen Chain, this means DEGEN, not ETH."
      },
      {
        "title": "Fee Note",
        "body": "PoidhV3 takes a 2.5% fee on accepted claim payouts, deducted only at acceptance. The full msg.value is held in escrow until then. The fee is paid in the chain's native token — ETH on Arbitrum and Base, DEGEN on Degen Chain."
      },
      {
        "title": "Error Reference",
        "body": "ErrorCauseFixContractsCannotCreateBounties()Wallet is a smart contractUse an EOA private keyMinimumBountyNotMet()Amount below MIN_BOUNTY_AMOUNTIncrease --value (0.001 ETH on Arbitrum/Base, 1000 DEGEN on Degen)MinimumContributionNotMet()Contribution below MIN_CONTRIBUTIONIncrease --value when joining open bountyNoEther()--value was 0 or omittedAdd --valueWrongCaller()Not the bounty issuerUse the issuer's private keyVotingOngoing()Active vote in progressWait for deadline, then resolveVoteVotingEnded()Deadline passed without resolutionCall resolveVoteNotSoloBounty()Open bounty with contributors tried direct acceptUse submitClaimForVote insteadClaimAlreadyAccepted()Claim was already acceptedNothing to doBountyClaimed()Bounty already finalizedNothing to doBountyClosed()Bounty was cancelledNothing to doBountyNotFound()Invalid bounty IDCheck bounty IDClaimNotFound()Invalid claim IDCheck claim IDIssuerCannotClaim()Issuer tried to submit a claim on their own bountyDifferent wallet must claimNotActiveParticipant()Caller is not a participant or has withdrawnMust be an active contributorMaxParticipantsReached()Open bounty has 150 contributorsWait for a slot to free upNothingToWithdraw()No pending balanceCheck pendingWithdrawals(address) firstVoteWouldPass()Tried to reset a vote that would passCannot override a winning vote"
      }
    ],
    "body": "Overview\n\nThis skill interacts with the PoidhV3 contracts on Arbitrum, Base, and Degen Chain to:\n\nPost bounties (solo or open)\nEvaluate claim submissions using vision — fetch the image URI from each claim and compare against the bounty description\nAccept the winning claim (solo bounty) or initiate + resolve a vote (open bounty)\n\npoidh (\"pics or it didn't happen\") is a fully on-chain bounty protocol. Claimants submit photo proof, and the bounty issuer (or contributors via vote) accepts the best claim to release funds.\n\n⚠️ The PoidhV3 contract enforces msg.sender == tx.origin. Only EOA wallets can create or accept bounties. Smart contract wallets (Safe, etc.) will revert with ContractsCannotCreateBounties.\n\nRequired Environment Variables\nVariable\tDescription\nPRIVATE_KEY\tPrivate key of the EOA signing transactions (hex, with or without 0x prefix)\nRPC_URL\tRPC URL for the target chain\nPOIDH_CHAIN\tTarget chain: arbitrum, base, or degen\n\nPOIDH_CONTRACT_ADDRESS is resolved automatically from POIDH_CHAIN — do not set it manually.\n\nSupported Chains\nChain\tContract Address\tExplorer\nArbitrum\t0x5555Fa783936C260f77385b4E153B9725feF1719\tarbiscan.io\nBase\t0x5555Fa783936C260f77385b4E153B9725feF1719\tbasescan.org\nDegen Chain\t0x18E5585ca7cE31b90Bc8BB7aAf84152857cE243f\texplorer.degen.tips\n\n⚠️ Minimum amounts differ by chain. On Arbitrum and Base: 0.001 ETH minimum bounty, 0.00001 ETH minimum contribution. On Degen Chain: 1000 DEGEN minimum bounty, 10 DEGEN minimum contribution. Always verify on-chain before posting:\n\ncast call $POIDH_CONTRACT_ADDRESS \"MIN_BOUNTY_AMOUNT()(uint256)\" --rpc-url $RPC_URL\ncast call $POIDH_CONTRACT_ADDRESS \"MIN_CONTRIBUTION()(uint256)\" --rpc-url $RPC_URL\n\n\nResolve the contract address at the start of every session:\n\nif [ \"$POIDH_CHAIN\" = \"degen\" ]; then\n  POIDH_CONTRACT_ADDRESS=\"0x18E5585ca7cE31b90Bc8BB7aAf84152857cE243f\"\nelse\n  # arbitrum and base share the same address\n  POIDH_CONTRACT_ADDRESS=\"0x5555Fa783936C260f77385b4E153B9725feF1719\"\nfi\n\n\nThe poidh.xyz URL also changes per chain:\n\nif [ \"$POIDH_CHAIN\" = \"arbitrum\" ]; then\n  POIDH_BASE_URL=\"https://poidh.xyz/arbitrum\"\n  POIDH_V2_OFFSET=180\nelif [ \"$POIDH_CHAIN\" = \"degen\" ]; then\n  POIDH_BASE_URL=\"https://poidh.xyz/degen\"\n  POIDH_V2_OFFSET=1197\nelse\n  POIDH_BASE_URL=\"https://poidh.xyz/base\"\n  POIDH_V2_OFFSET=986\nfi\n\nPart 1: Posting a Bounty\nCheck Minimum Bounty Amount\ncast call $POIDH_CONTRACT_ADDRESS \"MIN_BOUNTY_AMOUNT()(uint256)\" --rpc-url $RPC_URL\n\nPost a Solo Bounty\n\nSolo = only you fund it; you accept claims directly with no vote required.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"createSoloBounty(string,string)\" \\\n  \"<BOUNTY_NAME>\" \\\n  \"<BOUNTY_DESCRIPTION>\" \\\n  --value <AMOUNT> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\n\nExample:\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"createSoloBounty(string,string)\" \\\n  \"Brooklyn Bridge at sunset\" \\\n  \"High quality photo of the Brooklyn Bridge during golden hour. Must show the full span.\" \\\n  --value 0.001ether \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nPost an Open Bounty\n\nOpen = others can co-fund; claim acceptance requires a contributor-weighted vote.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"createOpenBounty(string,string)\" \\\n  \"<BOUNTY_NAME>\" \\\n  \"<BOUNTY_DESCRIPTION>\" \\\n  --value <AMOUNT> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nGet the Bounty ID After Posting\ncast receipt <TX_HASH> --rpc-url $RPC_URL --json | \\\n  python3 -c \"\nimport sys, json\nreceipt = json.load(sys.stdin)\nfor log in receipt['logs']:\n    if log['address'].lower() == '${POIDH_CONTRACT_ADDRESS}'.lower() and len(log['topics']) >= 2:\n        bounty_id = int(log['topics'][1], 16)\n        frontend_id = bounty_id + ${POIDH_V2_OFFSET}\n        print(f'Bounty ID: {bounty_id}')\n        print(f'View at: ${POIDH_BASE_URL}/bounty/{frontend_id}')\n        break\n\"\n\nPart 2: Evaluating Claims\n\nWhen the user wants to pick a winner, the agent must:\n\nFetch all claims for the bounty\nRetrieve each claim's URI from the NFT contract\nFetch and evaluate the content against the bounty description\nPick the best match\n\nClaim submissions are freeform — the URI could point to an image, a video, a tweet, a GitHub PR, a webpage, a document, or anything else. Evaluate whatever you find against what the bounty asked for.\n\nStep 1: Fetch Claims for a Bounty\ncast call $POIDH_CONTRACT_ADDRESS \\\n  \"getClaimsByBountyId(uint256,uint256)(tuple(uint256,address,uint256,address,string,string,uint256,bool)[])\" \\\n  <BOUNTY_ID> 0 \\\n  --rpc-url $RPC_URL\n\n\nReturns up to 10 claims (most recent first). Increment offset by 10 to paginate. Each claim tuple: (id, issuer, bountyId, bountyIssuer, name, description, createdAt, accepted)\n\nThe name and description fields on the claim are also set by the claimant and may give useful context about what they submitted.\n\nStep 2: Get the URI for Each Claim\n# Get NFT contract address\nNFT_ADDRESS=$(cast call $POIDH_CONTRACT_ADDRESS \"poidhNft()(address)\" --rpc-url $RPC_URL)\n\n# Get token URI for a specific claim\ncast call $NFT_ADDRESS \"tokenURI(uint256)(string)\" <CLAIM_ID> --rpc-url $RPC_URL\n\nStep 3: Resolve the URI\n\nConvert non-HTTP URIs to fetchable URLs:\n\nuri = \"<URI_FROM_TOKEN>\"\nif uri.startswith(\"ipfs://\"):\n    url = uri.replace(\"ipfs://\", \"https://ipfs.io/ipfs/\")\nelif uri.startswith(\"ar://\"):\n    url = uri.replace(\"ar://\", \"https://arweave.net/\")\nelse:\n    url = uri  # already HTTP\n\n\nIf the URL returns JSON metadata (standard ERC721 format), check for an image or animation_url field and resolve those too:\n\nimport requests\n\nresponse = requests.get(url)\ntry:\n    meta = response.json()\n    # Prefer animation_url (video/interactive) over image if both present\n    content_url = meta.get(\"animation_url\") or meta.get(\"image\") or url\n    if content_url.startswith(\"ipfs://\"):\n        content_url = content_url.replace(\"ipfs://\", \"https://ipfs.io/ipfs/\")\nexcept Exception:\n    content_url = url  # URI points directly to the content\n\nStep 4: Evaluate the Content\n\nFetch and review the content at content_url. Use the appropriate method based on what you find:\n\nImage — use native vision to view it directly\nWebpage / tweet / article — use the web fetch tool to read the content\nVideo — note the URL and evaluate based on the thumbnail or any available metadata\nDocument / PDF — fetch and read the text content\n\nEvaluate each claim against the bounty name and description on:\n\nRelevance — does the submission match what was actually asked for?\nQuality — is it complete, clear, and unambiguous?\nAuthenticity — does it appear genuine and original (not recycled or faked)?\n\nPick the claim with the highest overall score. Present your reasoning to the user before executing any transaction.\n\nPart 3: Accepting a Winning Claim — Solo Bounty\n\nFor solo bounties (and open bounties where no external contributors ever joined), the issuer accepts directly. This immediately finalizes the bounty, credits the claimant payout to pendingWithdrawals, takes the 2.5% protocol fee, and transfers the claim NFT to the issuer.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"acceptClaim(uint256,uint256)\" \\\n  <BOUNTY_ID> <CLAIM_ID> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nPart 4: Accepting a Winning Claim — Open Bounty (Vote Flow)\n\nFor open bounties where external contributors have joined, direct accept is blocked. Use the two-step vote flow.\n\nCheck if External Contributors Exist\ncast call $POIDH_CONTRACT_ADDRESS \\\n  \"everHadExternalContributor(uint256)(bool)\" \\\n  <BOUNTY_ID> \\\n  --rpc-url $RPC_URL\n\n\nIf false, fall back to acceptClaim (Part 3). If true, proceed with the vote flow below.\n\nStep 1: Submit the Chosen Claim for Vote (Issuer Only)\n\nThe issuer's full contribution weight is automatically cast as a YES vote at this point.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"submitClaimForVote(uint256,uint256)\" \\\n  <BOUNTY_ID> <CLAIM_ID> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\n\nAfter this call, other contributors have 2 days to vote YES/NO via the poidh.xyz UI or by calling voteClaim(bountyId, bool) directly.\n\nStep 2: Check Vote Status\ncast call $POIDH_CONTRACT_ADDRESS \\\n  \"bountyVotingTracker(uint256)(uint256,uint256,uint256)\" \\\n  <BOUNTY_ID> \\\n  --rpc-url $RPC_URL\n# Returns: yes_weight, no_weight, deadline_timestamp\n\npython3 -c \"import time; deadline=<DEADLINE>; print('Voting ended' if time.time() > deadline else f'Voting ends in {int((deadline - time.time())/3600)}h')\"\n\nStep 3: Resolve the Vote (Permissionless)\n\nAfter the 2-day window closes, anyone can resolve. If YES weight > 50% of total weight, the claim is accepted and funds are distributed.\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"resolveVote(uint256)\" \\\n  <BOUNTY_ID> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nPart 5: Submitting a Claim on Someone Else's Bounty\n\nAny EOA (except the bounty issuer) can submit a claim on an active open or solo bounty. This is how the agent acts as a claimant rather than an issuer. No native token is required to submit a claim — only gas.\n\nThe uri is the proof of completion — it can be anything: an IPFS image hash, a direct image URL, a tweet, a GitHub link, a webpage, a video, etc. It gets minted into a claim NFT at submission time.\n\nCheck That the Bounty is Active\n\nBefore submitting, verify the bounty exists, is not finalized, and has no ongoing vote:\n\ncast call $POIDH_CONTRACT_ADDRESS \\\n  \"bounties(uint256)(uint256,address,string,string,uint256,address,uint256,uint256)\" \\\n  <BOUNTY_ID> \\\n  --rpc-url $RPC_URL\n# Returns: id, issuer, name, description, amount, claimer, createdAt, claimId\n# claimer == 0x0 means active; claimer == issuer means cancelled; claimer == other means already won\n\n\nAlso confirm no vote is currently in progress:\n\ncast call $POIDH_CONTRACT_ADDRESS \\\n  \"bountyCurrentVotingClaim(uint256)(uint256)\" \\\n  <BOUNTY_ID> \\\n  --rpc-url $RPC_URL\n# Returns 0 if no active vote — safe to submit\n\nSubmit the Claim\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"createClaim(uint256,string,string,string)\" \\\n  <BOUNTY_ID> \\\n  \"<CLAIM_NAME>\" \\\n  \"<CLAIM_DESCRIPTION>\" \\\n  \"<PROOF_URI>\" \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nCLAIM_NAME — short title for the submission\nCLAIM_DESCRIPTION — explanation of how the bounty was completed\nPROOF_URI — the actual proof (image URL, IPFS URI, tweet URL, GitHub link, etc.)\n\nExample:\n\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"createClaim(uint256,string,string,string)\" \\\n  42 \\\n  \"Brooklyn Bridge golden hour\" \\\n  \"Took this photo at 7:43pm on the Manhattan side. Full span visible with reflection in the water.\" \\\n  \"ipfs://QmXyz...\" \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nGet the Claim ID After Submitting\ncast receipt <TX_HASH> --rpc-url $RPC_URL --json | \\\n  python3 -c \"\nimport sys, json\nreceipt = json.load(sys.stdin)\nfor log in receipt['logs']:\n    if log['address'].lower() == '$POIDH_CONTRACT_ADDRESS'.lower() and len(log['topics']) >= 2:\n        claim_id = int(log['topics'][1], 16)\n        print(f'Claim ID: {claim_id}')\n        break\n\"\n\nImportant Constraints\nThe agent's wallet (PRIVATE_KEY) cannot be the bounty issuer — IssuerCannotClaim will revert\nSubmitting is blocked while a vote is active on that bounty — VotingOngoing will revert\nThe bounty must still be open — finalized or cancelled bounties will revert\nThere is no limit to the number of claims per bounty; the issuer picks the best one\nPart 6: Withdrawing Funds\n\nAfter winning a bounty as claimant, funds are credited to pendingWithdrawals and must be explicitly collected. The bounty payout minus the 2.5% protocol fee is available immediately after acceptClaim or resolveVote finalizes.\n\nCheck Pending Balance\ncast call $POIDH_CONTRACT_ADDRESS \\\n  \"pendingWithdrawals(address)(uint256)\" \\\n  <YOUR_ADDRESS> \\\n  --rpc-url $RPC_URL\n\nWithdraw to Your Own Address\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"withdraw()\" \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\nWithdraw to a Different Address\ncast send $POIDH_CONTRACT_ADDRESS \\\n  \"withdrawTo(address)\" \\\n  <RECIPIENT_ADDRESS> \\\n  --private-key $PRIVATE_KEY \\\n  --rpc-url $RPC_URL\n\n\nwithdraw() sends the entire pending balance in one call. Check balance first to confirm funds are available before sending the transaction.\n\nAgent Decision Flow\nPosting a Bounty\nAsk for: name, description, amount (ETH on Arbitrum/Base, DEGEN on Degen Chain), type (solo or open — default solo)\nConfirm with user before sending — this spends real ETH (or DEGEN on Degen Chain)\nRun createSoloBounty or createOpenBounty\nReturn tx hash and $POIDH_BASE_URL/bounty/<bountyId + $POIDH_V2_OFFSET>\nSubmitting a Claim\nAsk for: bounty ID, proof URI (image, link, IPFS hash, etc.), claim name, claim description\nVerify the bounty is active and has no ongoing vote\nConfirm the agent's wallet is not the bounty issuer\nConfirm with user before sending\nCall createClaim(bountyId, name, description, uri)\nReturn the claim ID and tx hash\nEvaluating and Accepting\nAsk for the bounty ID\nCheck everHadExternalContributor to determine the correct acceptance path\nFetch all active (non-accepted) claims via getClaimsByBountyId\nFor each claim: get tokenURI, resolve URI, evaluate content using the appropriate tool (vision for images, web fetch for links, etc.)\nPresent recommended winner + reasoning to user, confirm before transacting\nSolo / no external contributors: acceptClaim(bountyId, claimId)\nOpen with external contributors: submitClaimForVote(bountyId, claimId), inform user contributors have 2 days to vote, then resolveVote after deadline\nNative Token Amount Reference\nHuman amount\tCast value\n0.001 ETH\t0.001ether\n0.01 ETH\t0.01ether\n1 ETH\t1ether\n1000 DEGEN\t1000ether\n10 DEGEN\t10ether\n\ncast uses ether as a unit label for any 18-decimal token. On Degen Chain, this means DEGEN, not ETH.\n\nFee Note\n\nPoidhV3 takes a 2.5% fee on accepted claim payouts, deducted only at acceptance. The full msg.value is held in escrow until then. The fee is paid in the chain's native token — ETH on Arbitrum and Base, DEGEN on Degen Chain.\n\nError Reference\nError\tCause\tFix\nContractsCannotCreateBounties()\tWallet is a smart contract\tUse an EOA private key\nMinimumBountyNotMet()\tAmount below MIN_BOUNTY_AMOUNT\tIncrease --value (0.001 ETH on Arbitrum/Base, 1000 DEGEN on Degen)\nMinimumContributionNotMet()\tContribution below MIN_CONTRIBUTION\tIncrease --value when joining open bounty\nNoEther()\t--value was 0 or omitted\tAdd --value\nWrongCaller()\tNot the bounty issuer\tUse the issuer's private key\nVotingOngoing()\tActive vote in progress\tWait for deadline, then resolveVote\nVotingEnded()\tDeadline passed without resolution\tCall resolveVote\nNotSoloBounty()\tOpen bounty with contributors tried direct accept\tUse submitClaimForVote instead\nClaimAlreadyAccepted()\tClaim was already accepted\tNothing to do\nBountyClaimed()\tBounty already finalized\tNothing to do\nBountyClosed()\tBounty was cancelled\tNothing to do\nBountyNotFound()\tInvalid bounty ID\tCheck bounty ID\nClaimNotFound()\tInvalid claim ID\tCheck claim ID\nIssuerCannotClaim()\tIssuer tried to submit a claim on their own bounty\tDifferent wallet must claim\nNotActiveParticipant()\tCaller is not a participant or has withdrawn\tMust be an active contributor\nMaxParticipantsReached()\tOpen bounty has 150 contributors\tWait for a slot to free up\nNothingToWithdraw()\tNo pending balance\tCheck pendingWithdrawals(address) first\nVoteWouldPass()\tTried to reset a vote that would pass\tCannot override a winning vote"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/saltoriousSIG/poidh",
    "publisherUrl": "https://clawhub.ai/saltoriousSIG/poidh",
    "owner": "saltoriousSIG",
    "version": "1.0.3",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/poidh",
    "downloadUrl": "https://openagent3.xyz/downloads/poidh",
    "agentUrl": "https://openagent3.xyz/skills/poidh/agent",
    "manifestUrl": "https://openagent3.xyz/skills/poidh/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/poidh/agent.md"
  }
}