cleanyourtv-app
Clean Your TV를 위한 커뮤니티 제작 모바일 앱
특정 지역 종 관찰 요청을 펀딩하고, iNaturalist 관찰을 검증·보상
Fund a call for sightings of a species in a place. Anyone submits an iNaturalist observation; GenLayer validators check it, look at the photos when the call asks, and pay the observer's wallet.
기타TypeScript · PythonGitHub @bars26온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Paid calls for wildlife sightings, checked on iNaturalist by GenLayer validators who look at the photos
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Paid calls for wildlife sightings. Anyone funds a call; naturalists post on iNaturalist as they always do; GenLayer validators check each sighting, look at the photos when the call asks for something specific, and pay the observer.
Conservation work runs on records: where an invasive hornet is nesting, whether hedgehogs still breed in a town, whether a rare orchid flowered this year. Millions of people already photograph wildlife and post it to iNaturalist, where a community identifies every record. But nobody pays for the one record that matters, and when someone tries (a bounty for nests, a reward for a first county record), every sighting has to be checked by hand and every payout trusted to whoever holds the money.
FieldCall turns that into a contract:
MEETS, NOT_MEETS or UNCLEAR; they must agree. They never re-identify the
species: the iNaturalist community already did.0x… address to their profile and anyone presses Collect.Live app: fieldcall-bars26.vercel.app. Paste any iNaturalist observation and see, without a wallet, which open calls it would earn and why. Writes need MetaMask on GenLayer Studio (chain 61999); Test GEN funds your wallet.
Contract: 0x58576b0a8C0091b8E7E276EDCa9b5D2d9bC826aE on GenLayer Studio.
MEETS, NOT_MEETS, UNCLEAR) so their agreement is strict. Verified on Studio: a nest photo and a photo of an adult
hornet on a branch, from the same observer on the same day, get opposite answers.scripts/demo.mjs opened two demo calls with test wallets and submitted real observations of the yellow-legged (Asian) hornet,
Vespa velutina, which the UK asks the public to report. Every transaction, reason, evidence packet and the balance
reconciliation are in docs/REPRODUCTION.md.
| Call | Observation | Ruling and stored reason |
|---|---|---|
| Asian hornet nests, UK, 0.5 GEN, photo condition "The photo shows a hornet nest" | 397236824: a nest in a tree, Romsey, 2026-08-20 | Qualifies. Validators looked at the photo and it shows a nest. A co-funder's fresh reading confirmed it. The observer has no wallet in their profile, so the reward is held for them |
| same | 397236834: an adult hornet on a branch, same observer, same day | Does not qualify: validators looked at three photos, NOT_MEETS each |
| same | 411158753: a European hornet, the native lookalike | Does not qualify: Vespa crabro is not Vespa velutina (decided in code; the scout's fresh reading agreed) |
| same | 411204951: an Asian hornet in France | Does not qualify: not inside the United Kingdom |
| same | 182971213: Hull, 2023 | Does not qualify: outside the call's dates |
| Asian hornet sightings, UK, 0.25 GEN, 2 per observer | three adults by the same observer | Qualifies, qualifies, then refused: the observer reached the call's limit of 2 |
Also refused on-chain, with the GEN sent back: a taxon name instead of an id, a taxon and a place iNaturalist does not have, a
call that has already ended, a reward below 0.1 GEN, a pot smaller than one reward, a start date of 2026-02-31, and a 0.05 GEN
top-up (below the 0.1 GEN minimum). And refused by the contract: submitting an observation that is already open, already earned
its reward, or was already submitted three times; a scout paying out early (only a funder can); collecting a held reward before
the observer links a wallet; and closing a call before its collect date. The contract's balance was reconciled
with totals() (open pots plus reserved rewards) at three points of the run, each time after every transfer had finalized.
From the live app with MetaMask: a tester opened a third call from the Live hedgehogs, UK preset (photo condition
"The photo shows a living hedgehog") and submitted three real observations: a hedgehog walking on a road qualified
(validators looked: MEETS, reward held for its observer), a dead hedgehog did not (NOT_MEETS), and a live hedgehog
whose observer opened their account two days before the sighting did not (the call requires 30 days; decided in code).
Transactions in docs/REPRODUCTION.md.
| Rule | Why |
|---|---|
The reward goes only to the 0x address in the observer's own iNaturalist profile | Submitting someone else's observation cannot redirect their reward; anyone can submit, nobody can steal |
| Taxonomy is the iNaturalist community's: the observation's identification must be the call's taxon or below it | Validators judge the photo condition only; a lookalike species fails in code, not by opinion |
| Research grade, not captive, inside the place, inside the dates, located precisely enough, account old enough: all in code | Every validator gets the same answer from the same record; no model judgement where a field decides |
| A photo condition is answered per photo with a fixed answer set; the first photo that clearly shows it decides | Strict consensus on an image judgement; a vague photo is UNCLEAR and reserves nothing |
| One payout per observation per call, at most N per observer, and a funder's wallet is never paid by its own call | One prolific account, or the sponsor, cannot drain the pot |
| Only the side a ruling goes against asks for a fresh reading, once each, inside 10 minutes | An identification that changes can still be read; nobody spends the other side's answer |
| Early settlement only against your own interest (a funder pays now, the submitter accepts a refusal) | The submitter cannot rush a payout; funders cannot rush a refusal |
iNaturalist outages, unreadable profiles and photos are UNCLEAR: nothing reserved, submit again | An outage never decides a sighting |
| Held rewards wait until the collect date (call end + 30 days), then return to the pot; the pot returns to funders pro rata | Money never strands; observers who join late still get paid |
Closing does a fixed amount of work; each funder's share is then returned by its own refund transaction, which anyone can send (always to that funder) | No call can grow so large that closing it runs out of gas and strands the funders' GEN |
| Funders, observer counts and submission counts live in their own maps, never in a list on the call; top-ups are at least 0.1 GEN; one observation can be submitted to a call at most 3 times | Spam cannot make any write more expensive than the first one |
Payable calls never revert; they refund and return REFUNDED: <reason>, including for dates that do not exist (2026-02-31) |
get_calls and one get_sightings
call, CDN-cached; iNaturalist is read straight from the browser.pip install -r requirements.txt
genvm-lint check contracts/field_call.py
pytest tests/direct/ -v # 55 tests: iNaturalist, profiles, photos and the LLM mocked
npm install
node scripts/deploy.mjs
node scripts/verify-code.mjs <address>
node scripts/demo.mjs <address> # the live run above (about 30 minutes)
node scripts/reproduction.mjs # regenerate docs/REPRODUCTION.md
cd frontend && cp .env.example .env.local && npm run dev
close() looped over every sighting and every funder in one transaction, and
both lists could be padded cheaply. Now close() only moves the pot and the expired held rewards into returnable; every
funder is then repaid by refund(call_id, funder), one bounded transaction each, sent by anyone, in any order, with the
last one taking the rounding remainder. Funders, per-observer counts and submission counts moved out of the call record into
their own maps, top-ups are at least 0.1 GEN, and an observation can be submitted to a call at most three times.
test_stress_hundreds_of_funders_and_refused_sightings_still_close_and_repay_everyone pads a call with 301 funders and 120
refused submissions, checks that close() reads no sighting and no funder, then repays all 301 and checks every wei left.create_call checks that starts and ends are real calendar dates before any date
arithmetic, so 2026-02-31 returns REFUNDED: ... with the GEN, instead of raising and keeping it; covered by tests that
record every transfer and by the live run.Observations and photos are © their authors on iNaturalist and are shown with their attribution and licence.
MIT licensed.
| GenLayer keeps the value of a reverted call |