<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Meteor Network</title>
    <description>The latest articles on DEV Community by Meteor Network (@meteor_network).</description>
    <link>https://dev.to/meteor_network</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4172310%2F3899a64d-002f-4eee-bec5-67a74b8fcdf2.png</url>
      <title>DEV Community: Meteor Network</title>
      <link>https://dev.to/meteor_network</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/meteor_network"/>
    <language>en</language>
    <item>
      <title>Why We Stopped Paying Per Like: Building a Bot-Farm-Resistant Reward System for a Meme Feed</title>
      <dc:creator>Meteor Network</dc:creator>
      <pubDate>Fri, 09 Oct 2026 02:40:03 +0000</pubDate>
      <link>https://dev.to/meteor_network/why-we-stopped-paying-per-like-building-a-bot-farm-resistant-reward-system-for-a-meme-feed-18ip</link>
      <guid>https://dev.to/meteor_network/why-we-stopped-paying-per-like-building-a-bot-farm-resistant-reward-system-for-a-meme-feed-18ip</guid>
      <description>&lt;p&gt;How AuraBay will replace pay-per-like with daily pools, human verification, escrow and signed on-chain mints on Avalanche.&lt;/p&gt;

&lt;p&gt;The first reward rule we shipped for AuraBay fit in one line: when a post gets a like, pay its author 1 Spark.&lt;/p&gt;

&lt;p&gt;Any developer who has watched a "like-to-earn" app die already knows how that goes. If a like has a fixed price and nothing else stands in the way, a bot farm makes money by the hour. Fifty accounts like each other's memes and every one of them pays out. You haven't built a meme economy. You've built an API for printing points.&lt;/p&gt;

&lt;p&gt;So we turned it off and put something sturdier at the core. The per-like reward isn't gone for good: it's planned to come back later as a small bonus on top, running behind the same anti-farming rules as everything else. This post covers what's underneath it: daily pools, weighted actions, verified-human tiers, a reputation multiplier, escrow with clawbacks, and finally an on-chain mint gated by a server signature. Everything below comes from the actual AuraBay codebase (Next.js + Supabase + Solidity on Avalanche), with file names so you can follow along.&lt;/p&gt;

&lt;p&gt;Status check, up front: AuraBay is still in development and not live yet. The smart contracts are in development too, and the reward switches (rewards_enabled, echo_rewards_enabled) default to false. The per-like Spark bonus (like_reward_spark) is off too. Every number in this post is a row in an app_config table, not a constant, and we expect to tune them.&lt;/p&gt;

&lt;p&gt;The core idea: pools first, prices second&lt;/p&gt;

&lt;p&gt;When per-like pay is the whole system, total payout grows with activity, fake activity included. A daily pool fixes the total first. Users then compete for shares of it. That's where the bulk of rewards will come from.&lt;/p&gt;

&lt;p&gt;The small per-like Spark reward we plan to switch on later sits on top of the pool and goes through the same gates you'll see below. Only scoring likes count, so tier 0 accounts and self-likes earn nothing. The per-creator and per-day caps apply, and the reward waits in escrow. A farm that can't get a like to score can't get it paid either.&lt;/p&gt;

&lt;p&gt;Once a day (on UTC time), compute_epoch(date) in supabase/schema.sql scores the previous day:&lt;/p&gt;

&lt;p&gt;-- supabase/schema.sql (defaults, simplified)&lt;br&gt;
insert into app_config (key, value) values&lt;br&gt;
  ('pool_per_active_user', '50'),&lt;br&gt;
  ('pool_min', '1000'),&lt;br&gt;
  ('pool_max', '50000'),&lt;br&gt;
  ('creator_share', '0.70'),&lt;br&gt;
  ('curator_share', '0.30'),&lt;br&gt;
  ('tier_weights', '{"0":0,"1":0.25,"2":1.0}'),&lt;br&gt;
  ('interaction_weights', '{"like":1,"respark":1.5,"save":2,"remix":5}'),&lt;br&gt;
  ('same_pair_daily_limit', '3'),&lt;br&gt;
  ('curator_daily_interaction_limit', '30'),&lt;br&gt;
  ('escrow_hours', '48');&lt;/p&gt;

&lt;p&gt;The pool size is 50 × active verified users, clamped to the range 1,000–50,000, plus whatever went unallocated the day before. An "active" user is tier 2 (more on tiers below) and had scoring interactions on at least 3 different days in the last 7. So a farm that spins up 1,000 fresh accounts doesn't grow the pool on day one, because none of those accounts is active yet.&lt;/p&gt;

&lt;p&gt;The pool then splits:&lt;/p&gt;

&lt;p&gt;70% to creators, in proportion to the "quality" each post earned&lt;/p&gt;

&lt;p&gt;30% to curators, the people whose interactions produced that quality&lt;/p&gt;

&lt;p&gt;Not all clicks are equal&lt;/p&gt;

&lt;p&gt;Each interaction has a weight. A like is cheap, a save means "I want this later", and a respark puts the meme on your own feed:&lt;/p&gt;

&lt;p&gt;Action&lt;/p&gt;

&lt;p&gt;Weight&lt;/p&gt;

&lt;p&gt;like&lt;/p&gt;

&lt;p&gt;1&lt;/p&gt;

&lt;p&gt;respark&lt;/p&gt;

&lt;p&gt;1.5&lt;/p&gt;

&lt;p&gt;save&lt;/p&gt;

&lt;p&gt;2&lt;/p&gt;

&lt;p&gt;remix&lt;/p&gt;

&lt;p&gt;5&lt;/p&gt;

&lt;p&gt;A post's quality is the sum of tierWeight × auraScore × actionWeight over its scoring interactions. The gatekeeping happens when an interaction is recorded. This is scoreInteraction from src/lib/phase0/rules.ts, lightly trimmed:&lt;/p&gt;

&lt;p&gt;// src/lib/phase0/rules.ts&lt;br&gt;
export function scoreInteraction(input: InteractionScoreInput) {&lt;br&gt;
  const withinPair = input.scoringWithAuthorToday &amp;lt; input.pairLimit;   // 3&lt;br&gt;
  const withinCurator = input.scoringToday &amp;lt; input.curatorLimit;       // 30&lt;br&gt;
  const eligible = !input.self &amp;amp;&amp;amp; withinPair &amp;amp;&amp;amp; withinCurator;&lt;br&gt;
  const weight = eligible ? input.tierWeight * input.interactionWeight : 0;&lt;/p&gt;

&lt;p&gt;return { scoring: eligible &amp;amp;&amp;amp; weight &amp;gt; 0, weightSnapshot: eligible ? weight : 0 };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Three rules come out of those few lines:&lt;/p&gt;

&lt;p&gt;Self-likes count 0. They're stored so the UI stays honest, but they score nothing.&lt;/p&gt;

&lt;p&gt;At most 3 scoring interactions per creator per day. Fifty sock puppets all hammering one "main" account hit this wall fast.&lt;/p&gt;

&lt;p&gt;At most 30 scoring interactions per person per day. Curating is a skill, and nobody gets to do it in bulk.&lt;/p&gt;

&lt;p&gt;The weight is snapshotted when the interaction happens. If we retune interaction_weights next week, the change doesn't rewrite last week's history.&lt;/p&gt;

&lt;p&gt;Paying curators for being early&lt;/p&gt;

&lt;p&gt;The 30% curator share isn't split evenly. For each post, curators are ranked by when they first interacted, and each one's share is weight / √rank:&lt;/p&gt;

&lt;p&gt;// src/lib/phase0/rules.ts&lt;br&gt;
export function curatorPayouts(pot: number, curators: { userId: string; weight: number; rank: number }[]) {&lt;br&gt;
  const parts = curators.map((c) =&amp;gt; ({ userId: c.userId, share: c.weight / Math.sqrt(c.rank) }));&lt;br&gt;
  const denom = parts.reduce((sum, p) =&amp;gt; sum + p.share, 0);&lt;br&gt;
  return parts.map((p) =&amp;gt; ({ userId: p.userId, amount: denom &amp;gt; 0 ? (pot * p.share) / denom : 0 }));&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The first person to spot a banger gets a full share. The 100th gets a tenth of one. Piling onto memes that are already viral still pays a little, but finding them early pays much better. We used a square root instead of something like 1/rank because 1/rank falls off so fast that the second curator gets almost nothing.&lt;/p&gt;

&lt;p&gt;Two concentration caps keep any one person from draining a pool: 3% of the creator pool and 2% of the curator pool (each cap is at least 50 Spark). Anything above a cap rolls over into tomorrow's pool.&lt;/p&gt;

&lt;p&gt;A separate pool for comments: Echo&lt;/p&gt;

&lt;p&gt;Comments (we call them Echoes) get their own pool, scoreEchoEpoch in rules.ts. It works like the Spark pool but runs on comments: 20 per active user, clamped to 500–20,000, split among authors by the weighted comments they receive.&lt;/p&gt;

&lt;p&gt;The anti-spam rules mirror Spark: self-comments, comments from sybil-flagged accounts and flagged or deleted comments all count 0. Only one scoring comment per person per post counts, with at most 3 per author per day. A comment must also be at least 2 characters, and repeating the same text within 24 hours (comment_dedupe_hours) is rejected. "🔥" times 400 earns you nothing.&lt;/p&gt;

&lt;p&gt;Why a separate pool? Echo used to be tangled up with our reputation multiplier. Splitting them (commit #20, "Separate Echo points from Aura Score") made both easier to reason about and to tune separately.&lt;/p&gt;

&lt;p&gt;Aura Score: reputation as a multiplier&lt;/p&gt;

&lt;p&gt;Every interaction's weight is multiplied by the actor's Aura Score. It's a reputation value clamped to 0.5–2.0, not a balance you can spend. Tier 2 users start at 1.0 and tier 1 users at 0.75.&lt;/p&gt;

&lt;p&gt;A weekly cron (update_reputation() in SQL, mirrored by nextAuraScore in rules.ts) adjusts it:&lt;/p&gt;

&lt;p&gt;// src/lib/phase0/rules.ts (simplified)&lt;br&gt;
let value = input.auraScore;&lt;br&gt;
if (value &amp;gt; baseline) value = baseline + (value - baseline) * (1 - decay); // decay 2%/week toward 1.0&lt;br&gt;
if (input.qualifiedEarly) value += boost;                                 // +0.05&lt;br&gt;
value -= input.penaltyEvents * penalty;                                   // −0.2 each&lt;br&gt;
return clamp(value, 0.5, 2.0);&lt;/p&gt;

&lt;p&gt;+0.05 if you liked a post on the same day it finished in that day's top 10% by quality. That's a direct reward for good taste.&lt;/p&gt;

&lt;p&gt;−0.2 for each upheld flag on your content, each clawback, or being marked sybil.&lt;/p&gt;

&lt;p&gt;2% weekly decay toward 1.0, so a high score has to be maintained.&lt;/p&gt;

&lt;p&gt;Over time, accounts with a record of good curation carry more weight than fresh accounts. Fresh accounts are exactly what bot farms have plenty of.&lt;/p&gt;

&lt;p&gt;Verified humans only (at full weight)&lt;/p&gt;

&lt;p&gt;The tier weights {0: 0, 1: 0.25, 2: 1.0} do most of the anti-sybil work. Here's how tiers are assigned (computeTier in rules.ts, called from src/lib/phase0/service.ts):&lt;/p&gt;

&lt;p&gt;export function computeTier(input: TierInput): Tier {&lt;br&gt;
  const passportReady = input.passportScore != null &amp;amp;&amp;amp; input.passportScore &amp;gt;= input.passportThreshold; // 20&lt;br&gt;
  if (input.worldIdVerified || passportReady) return 2;&lt;/p&gt;

&lt;p&gt;const aged = input.accountAgeDays &amp;gt;= input.minAgeDays; // 7&lt;br&gt;
  const linked = input.xLinked || input.phoneVerified;&lt;br&gt;
  if (aged &amp;amp;&amp;amp; linked &amp;amp;&amp;amp; !input.recentAbuse) return 1;&lt;/p&gt;

&lt;p&gt;return 0;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Tier 0: everyone at signup. Your clicks show up in the counts but score zero.&lt;/p&gt;

&lt;p&gt;Tier 1: the account is at least 7 days old, has a linked X account or phone, and has no recent rate-limit abuse. Scores at 0.25×.&lt;/p&gt;

&lt;p&gt;Tier 2: a Human Passport score of at least 20, or a World ID proof. Scores at 1.0×.&lt;/p&gt;

&lt;p&gt;World ID nullifiers are canonicalized and unique per account, so one human can't verify two accounts. A linked wallet address can also belong to only one user. Only tier 2 accounts can flag posts, appear on the leaderboards, or synthesize (see below).&lt;/p&gt;

&lt;p&gt;Escrow, flags, and clawbacks&lt;/p&gt;

&lt;p&gt;Pool rewards aren't paid out right away. Every reward row goes into reward_ledger as pending, with settle_at = now() + 48h. An hourly cron runs settle_escrow(). The decision logic, from escrowTransition in rules.ts:&lt;/p&gt;

&lt;p&gt;if (status === "pending") {&lt;br&gt;
  if (upheld || sybil) return { kind: "clawback" };&lt;br&gt;
  if (now &amp;gt;= settleAt &amp;amp;&amp;amp; !underReview) return { kind: "settle" };&lt;br&gt;
  return { kind: "unchanged" };&lt;br&gt;
}&lt;br&gt;
// already settled, but a flag was upheld later? subtract it.&lt;br&gt;
if (amount &amp;gt; 0 &amp;amp;&amp;amp; (upheld || sybil)) return { kind: "adjust", amount: -amount };&lt;/p&gt;

&lt;p&gt;Tier 2 users can flag posts, up to a daily budget of 5 flags (daily_flag_budget). Once open flags reach a combined weight of 3, the post goes under review and its payouts freeze. An upheld flag cancels pending rewards. If the rewards had already settled, it writes a negative adjustment, and balances are allowed to go below zero. Authors have 7 days to appeal.&lt;/p&gt;

&lt;p&gt;Those 48 hours are the window where humans and heuristics catch what the formulas missed. A farm only finds out it was caught when its rewards come back as clawed_back instead of settled.&lt;/p&gt;

&lt;p&gt;From points to AURA: a signed, capped mint&lt;/p&gt;

&lt;p&gt;Spark and Echo are off-chain ledger points. AURA is an ERC-20 on Avalanche (AuraBayToken.sol, still in development). The bridge between them is synthesis. We're planning a ratio of 100 Spark + 40 Echo + 1 Nova → 100 AURA. The code today still mints 1 AURA per synthesis (auraOut), and the costs, output and daily caps are all config and contract parameters. Treat these numbers as a plan, not a promise. They may change before anything goes live.&lt;/p&gt;

&lt;p&gt;Nova is the newest ingredient (commit #24). Every 10 qualifying referrals credit 1 Nova. A referral only qualifies if a new account reaches a tier weight above zero and then likes, resparks or shares. Same-device signups are rejected, and so is anything past a burst limit of 5 per IP or device per hour.&lt;/p&gt;

&lt;p&gt;The design rule for synthesis: the contract never trusts the client and never touches points. The server checks everything, debits the balances in one database transaction (reserve_offchain_synthesis), and then signs an EIP-712 voucher valid for 10 minutes. The contract only verifies that voucher:&lt;/p&gt;

&lt;p&gt;// packages/hardhat/contracts/AuraBaySynthesis.sol (simplified)&lt;br&gt;
function synthesize(bytes32 authId, uint256 deadline, bytes calldata signature)&lt;br&gt;
    external whenNotPaused nonReentrant&lt;br&gt;
{&lt;br&gt;
    if (block.timestamp &amp;gt; deadline) revert AuthorizationExpired();&lt;br&gt;
    if (usedAuthorizations[authId]) revert AuthorizationUsed();&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bytes32 digest = _authorizationDigest(msg.sender, authId, sparkCost, echoCost, novaCost, auraOut, deadline);
if (ECDSA.recover(digest, signature) != authorizer) revert BadSignature();

usedAuthorizations[authId] = true;
_consumeCaps(msg.sender, auraOut); // per-user and global UTC-day ceilings
aura.mint(msg.sender, auraOut);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;A few details we're happy with:&lt;/p&gt;

&lt;p&gt;The costs are part of the signed payload. If an admin changes the rates, older vouchers stop matching and can't be replayed.&lt;/p&gt;

&lt;p&gt;Daily caps are checked twice. The API checks synthesis_daily_user_aura_cap and synthesis_daily_global_aura_cap (current defaults: 5 and 100 AURA, which we'll retune together with the ratio), and the contract enforces its own ceilings again.&lt;/p&gt;

&lt;p&gt;Only tier 2, non-sybil accounts with a linked wallet can request a voucher (synthesisDecision in src/lib/synthesis-policy.ts).&lt;/p&gt;

&lt;p&gt;Unused vouchers refund themselves. If the mint doesn't land before the deadline, release_synthesis_reservation returns the Spark, Echo and Nova.&lt;/p&gt;

&lt;p&gt;What we learned&lt;/p&gt;

&lt;p&gt;Don't let a fixed price per click be your whole economy. Fix the budget first and let users compete for shares of it. If you do pay per action, make sure only verified, capped, escrowed actions get paid.&lt;/p&gt;

&lt;p&gt;Rate-limit relationships, not just requests. The "3 per creator per day" rule stopped more farm patterns than any IP limit we tried.&lt;/p&gt;

&lt;p&gt;Rewards should be revocable for a while. Escrow turns "we got farmed" from a disaster into a database update.&lt;/p&gt;

&lt;p&gt;Keep every knob in config. We've retuned these numbers more times than we'd like to admit, and none of those changes needed a deploy.&lt;/p&gt;

&lt;p&gt;Give the chain as little to trust as possible. The contract checks a signature and two counters. All the judgment calls happen on the server, where they can be fixed.&lt;/p&gt;

&lt;p&gt;There's more coming (the meme feed has plenty of other ideas in the queue), but this reward system is the foundation everything else will build on.&lt;/p&gt;

&lt;p&gt;We're building AuraBay in public. Follow @AuraBayxMeteor on X and join our Discord for progress updates. And if you've built (or broken 😅) a reward system like this, tell us in the comments where you'd attack ours. Pool math, sybil resistance, the √rank curve: we want the critiques.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>blockchain</category>
      <category>crypto</category>
      <category>web3</category>
    </item>
    <item>
      <title>Meet Meteor Network: an Avalanche L1 for creatives (and our first app, AuraBay)</title>
      <dc:creator>Meteor Network</dc:creator>
      <pubDate>Fri, 09 Oct 2026 02:30:03 +0000</pubDate>
      <link>https://dev.to/meteor_network/meet-meteor-network-an-avalanche-l1-for-creatives-and-our-first-app-aurabay-3ki4</link>
      <guid>https://dev.to/meteor_network/meet-meteor-network-an-avalanche-l1-for-creatives-and-our-first-app-aurabay-3ki4</guid>
      <description>&lt;p&gt;&lt;strong&gt;Give creatives what they deserve.&lt;/strong&gt; That's the whole idea behind Meteor Network.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Meteor Network?
&lt;/h2&gt;

&lt;p&gt;Meteor Network is a Layer 1 blockchain we're building on Avalanche, made for creatives who build games, SocialFi and Web3 apps. &lt;strong&gt;METEOR&lt;/strong&gt; is the network token, and it's shared across the apps that live on it.&lt;/p&gt;

&lt;p&gt;We also want to make Web3 less intimidating. Alongside the chain, we're writing beginner-friendly guides on crypto, NFTs, Web3 games and the tools around them, so people can go from zero to their first transaction without drowning in jargon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our first app: AuraBay 🔺
&lt;/h2&gt;

&lt;p&gt;AuraBay is a meme feed where making good memes, and spotting them early, actually pays off.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎨 &lt;strong&gt;Make:&lt;/strong&gt; a built-in Studio with the most popular meme templates and an AI "Auto-Joke" button for captions.&lt;/li&gt;
&lt;li&gt;✨ &lt;strong&gt;React:&lt;/strong&gt; Spark (like), Save, Respark and Echo (comment).&lt;/li&gt;
&lt;li&gt;🏆 &lt;strong&gt;Earn:&lt;/strong&gt; a daily reward pool is split between creators &lt;em&gt;and&lt;/em&gt; the early curators who backed the best memes.&lt;/li&gt;
&lt;li&gt;🧍 &lt;strong&gt;Stay human:&lt;/strong&gt; only verified humans score at full weight, and anti-farming rules (no self-likes, daily caps, a 48h reward hold) keep bot farms from cashing in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AuraBay is currently will be on testnet soon, and every reward number is still being tuned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Meteor L1 and the METEOR token&lt;/li&gt;
&lt;li&gt;More creator apps on the network&lt;/li&gt;
&lt;li&gt;Online guides for Web3 beginners&lt;/li&gt;
&lt;li&gt;Later on, physical hubs: office, café and design-studio spaces for creatives&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Follow along
&lt;/h2&gt;

&lt;p&gt;We're building in public, and this blog is where we'll share the technical side: how we design rewards, fight bots and ship the chain.&lt;/p&gt;

&lt;p&gt;Follow us here, and follow AuraBay on X at &lt;a href="https://x.com/AuraBayxMeteor" rel="noopener noreferrer"&gt;@AuraBayxMeteor&lt;/a&gt; and discord (&lt;a href="https://discord.gg/yrFjNgYqbK" rel="noopener noreferrer"&gt;https://discord.gg/yrFjNgYqbK&lt;/a&gt;). Questions or feedback? Drop them in the comments, we read every one.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>avalanche</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
