Skip to content

beecoder77/MovrChain

Repository files navigation

MovrChain

The running app that proves you ran — and pays you for it.

Production: movr.muhsalmanabid.com

MovrChain is a Monad-native running tracker built for the post-run check-in. It allows runners to import GPX route data, replay their routes with statistics, attest the activity on-chain with zero-overhead finality, publish it to a global community feed, and claim milestone rewards. The app also features an achievement NFT system, staking pools with NFT-backed yield boosts, and community running clubs with decentralized treasuries.


Table of Contents

  1. Quick Start
  2. Core Application Flows
  3. Local Development & Frontend Setup
  4. Smart Contract Stack
  5. Security, Validation & Contract Rules
  6. Test & Audit Gate
  7. Verified Monad Testnet Deployments
  8. Contract Deployment Guide (Monad Testnet)
  9. Administrative & Operations Scripts
  10. Monad Testnet Network Details

Quick Start

For judges or quick manual verification, open the production app. It is pre-configured with active contracts on the Monad Testnet and includes a local sample run simulation.

  1. Install Dependencies:
 npm install
  1. Run Development Server:
 npm run dev
  1. Verify Locally:
  • Open http://localhost:5173.
  • Click the "Import" button.
  • Select "Load Sample Run" to load public/sample-run.gpx and test the full visual route replay and summary flow without needing a wallet.
  • To test the on-chain attestation and claims, connect a wallet on Monad Testnet. Desktop: browser extension (e.g. MetaMask). Phone: use Wallet app via WalletConnect (opens MetaMask / other mobile wallets).

Core Application Flows

MovrChain's user experience is split into distinct, highly interactive phases:

[Import + Parse GPX] ──► [Route Replay] ──► [Review Stats] ──► [Validate + Attest] ──► [Publish + Claim]

1. Import

Users upload standard GPX files (generated by Strava, Apple Watch, Garmin, etc.) containing GPS coordinates and time telemetry. The file is parsed in the browser via [gpx.ts](src/lib/gpx.ts) to calculate distance, duration, pace, and route points.

2. Animated Replay

Once loaded, a stat-focused view plays an animated trace of the run's GPX coordinates on an interactive map. In this screen, distance dominates the screen space, with pace and duration supporting it.

3. Summary

The user reviews a static summary of their effort. This screen lists total distance (km), average pace, duration, and the full route layout.

4. On-chain Validation, Verification & Claims

MovrChain supports two attestation modes:

  • Hackathon/testnet mode (selfAttestEnabled = true): runners submit their own wallet-bound route commitments, subject to hard validation limits.
  • Trusted attester mode (selfAttestEnabled = false): only ATTESTER_ROLE can submit through attestRunFor, allowing an oracle or backend verifier to become the production trust boundary.

Neither mode treats the route hash itself as a GPS proof. The contract binds the runner, metrics, and route commitment; trusted mode additionally restricts who may attest.

The "Verify & publish" pipeline validates the run in layers:

  1. Browser GPX validation
  • Rejects malformed XML, files with fewer than two track points, and routes with fewer than two valid finite coordinates.
  • Calculates distance from coordinates using the Haversine formula.
  • Uses recorded timestamps when available; otherwise estimates duration at a documented fallback pace.
  • Marks the bundled sample GPX as preview-only and disables on-chain verification for it.
  1. Deterministic wallet-bound commitment
  • The frontend hashes sampled route coordinates into routeCommit.
  • The run ID is computed as keccak256(abi.encode(runner, distanceMeters, durationSeconds, routeCommit)).
  • Including the runner address prevents another wallet from front-running the same commitment as its own activity. Binding the metrics prevents distance or duration from being swapped against an unrelated route commitment.
  1. Attestation contract validation
  • In trusted mode, rejects callers without ATTESTER_ROLE.
  • Requires non-zero distance and duration.
  • Rejects distances above 200 km and durations above 48 hours.
  • Rejects average speed above 10 m/s (approximately 36 km/h) as an anti-teleport sanity bound.
  • Limits each wallet to 24 attestations per UTC day.
  • Rejects an existing deterministic runHash.
  • Snapshots clubIdAtAttest; joining a club after the run cannot redirect that run's club reward.
  • Stores the accepted record, updates total distance, run count, best distance, and qualifying daily streaks, then emits RunAttested.
  • A streak advances only on ≥1 km days. Missing a UTC day decays the current streak; sub-1 km activity cannot preserve a stale streak.
  1. Authorized feed publication
  • MovrFeed accepts only a run already stored in MovrChainAttestation.
  • The publishing wallet must be the attested runner.
  • Each runHash can be published only once, and the run name must contain 1–64 bytes.
  • The owner can pause publication for moderation or incident response.
  1. Milestone claim validation
  • A run qualifies at ≥ 1 km; only its attested runner can claim.
  • Each runHash can be claimed once, and the reward pool must have enough MOVR.
  • The runner receives 1 MOVR per kilometer based on the attested distance.
  • If clubIdAtAttest was non-zero, an additive 1 MOVR per 10 km goes to that snapshotted club treasury. Claim-time club membership cannot create a club cut.
  1. Receipt and recovery checks
  • The UI waits for each transaction receipt and treats a reverted receipt as failure.
  • Before retrying, it reads attestation, publication, and claim state from the contracts so an already-confirmed step is not submitted twice.
  • After confirmation, targeted query refetches account for RPC indexing delay without freezing unrelated navigation.

5. Staking & Achievements

  • Achievements: The AchievementNFT contract defines milestone templates (e.g., First 5K, First Half Marathon, 7-Day Streak). Streak achievements require an active, time-decayed streak. Per-token boosts are snapshotted at mint, so later admin edits cannot corrupt transfer accounting.
  • Marketplace: Listings clear before payment and buyNFT is reentrancy-guarded.
  • Staking: Achievement and soulbound club-badge boosts are combined and capped by maxBoostBps.
  • Expected rewards UI: The Staking tab projects day / month / year yield from today’s rate × NFT boost, splits You keep vs To club using the donate %, and previews the amount field only when nothing is staked yet. While staked, the amount field is for stake/unstake only — the table stays on current stake. Estimates (30-day month) are not a guarantee of claimable rewardReserve.
  • Rate changes: Each account accrues using a locked rate for the current interval. configureRates applies to future intervals, not retroactively.
  • Solvency: Rewards are paid only from rewardReserve; user principal remains tracked separately in totalStaked. Partial claims preserve unpaid reward debt.
  • Club donation: Stakers may route 2–5% of claimed yield to the club snapshotted when they saved donate % (donateClubId). Claim donates only while they remain a member of that club; leaving skips donate until they save again. Joining another club does not redirect yield without re-saving.

6. Running Clubs

Discover and join clubs on the Clubs tab. Clubs are ranked by active treasury size and total clubmate runs.

  • One club per wallet: enforced by clubOf; leaving clears membership and burns the soulbound member NFT so rejoining works.
  • Manager Approval: Private clubs require approval from the club manager to join.
  • Treasury proposals: amounts are reserved at creation, preventing multiple active proposals from oversubscribing the same balance. Votes are rejected after voting closes. Only Captain/Admin can execute a passed proposal. Execute still works if the proposer left; proposers cannot cancel after a passed vote closes.
  • Challenges: only club managers can escrow treasury rewards. Durations are capped at 90 days / 3 months; managers can cancel and refund. Dust and zero-winner settlement return funds to the treasury, and approvals can be revoked before settlement.

Local Development & Frontend Setup

Setup Environment

The application contains baked-in, pre-deployed contract addresses in [contracts.ts](src/lib/contracts.ts), all pointing to source-verified Monad Testnet contracts. To deploy and run with your own contracts, set up overrides in .env.local at the root of the project:

# Override contract addresses
VITE_CONTRACT_ADDRESS=0xAttestationAddress
VITE_PROFILE_ADDRESS=0xProfileAddress
VITE_MOVR_TOKEN=0xTokenAddress
VITE_ACHIEVEMENT_NFT=0xAchievementNftAddress
VITE_STAKING=0xStakingAddress
VITE_CLUB_REGISTRY=0xClubRegistryAddress
VITE_CLUB_MEMBER_NFT=0xClubMemberNftAddress
VITE_CLUB_BADGE_NFT=0xClubBadgeNftAddress
VITE_CLUB_CHALLENGES=0xClubChallengesAddress
VITE_MILESTONE_REWARD=0xMilestoneRewardAddress
VITE_FEED_ADDRESS=0xFeedAddress

Static Assets Generation

The frontend includes utilities to generate customized athletic avatars and achievement badge SVGs:

  • Generate Avatars: Generates SVGs under public/brand/avatars/
    npm run generate:avatars
  • Generate Achievement Metadata/Art: Generates on-chain data URIs and metadata JSON
    npm run generate:art

Smart Contract Stack

The contracts are built using Foundry and are located under [contracts/src/](contracts/src/).

Contract Role
[MovrToken.sol](contracts/src/MovrToken.sol) Ecosystem utility ERC-20 token (MOVR), admin-minted under a hard 1B MOVR cap.
[MovrChainAttestation.sol](contracts/src/MovrChainAttestation.sol) Wallet-bound run validation, optional trusted-attester mode, club-at-attest snapshots, and live streak calculation.
[AchievementNFT.sol](contracts/src/AchievementNFT.sol) ERC-721 athletic achievements with mint-time boost snapshots and a reentrancy-guarded native MON marketplace.
[MovrStaking.sol](contracts/src/MovrStaking.sol) Principal-separated staking with funded reward reserves, non-retroactive rates, Achievement + ClubBadge boosts, and optional club donation.
[MovrProfile.sol](contracts/src/MovrProfile.sol) Unique lowercase handles, runner names, bios, and selected avatar IDs.
[MovrClubRegistry.sol](contracts/src/MovrClubRegistry.sol) Spawns clubs and membership; deploys per-club ClubTreasury as BeaconProxy (shared upgradeable logic).
[ClubMemberNFT.sol](contracts/src/ClubMemberNFT.sol) Soulbound membership badges confirming club alignment.
[ClubBadgeNFT.sol](contracts/src/ClubBadgeNFT.sol) Soulbound club contribution badges whose boosts are consumed by staking.
[MovrClubChallenges.sol](contracts/src/MovrClubChallenges.sol) Manager-controlled, duration-capped treasury challenges with cancel/refund and dust-safe settlement.
[MovrMilestoneReward.sol](contracts/src/MovrMilestoneReward.sol) One-claim run rewards with club routing fixed to the attestation-time snapshot.
[MovrFeed.sol](contracts/src/MovrFeed.sol) Pausable global index of one-shot published run hashes, telemetry, and timestamps.

Security, Validation & Contract Rules

These are release rules, not optional recommendations:

  1. Proof before reward: reward and publishing paths consume an existing attestation; they never accept raw frontend metrics.
  2. Deterministic identity: runHash binds runner, distance, duration, and routeCommit.
  3. Trust mode is explicit: testnet may use self-attestation; production must disable it unless the economic risk is accepted and grant ATTESTER_ROLE to a controlled verifier.
  4. Snapshot mutable context: club reward routing and NFT boosts are captured when the relevant run/token is created.
  5. No stale streaks: current streaks decay by UTC day; historical longest streak does not satisfy an active-streak claim.
  6. Principal is not rewards: staking principal (totalStaked) and funded rewards (rewardReserve) are separate.
  7. No treasury overcommit: active proposals reserve funds; challenges can spend only unreserved balance.
  8. Escrow must have an exit: challenges are manager-gated, duration-capped, cancellable, and settle dust back to treasury.
  9. Soulbound means lifecycle-complete: membership NFTs burn on leave; club badges cannot transfer.
  10. External value calls are guarded: marketplace and reward/treasury flows use reentrancy protection and checks-effects-interactions.
  11. Admin powers are bounded and observable: MOVR has a hard max supply; pause, roles, rates, and funding are explicit contract state.
  12. Proxy addresses are permanent after the UUPS cutover: update contracts/.env, root .env.local, and src/lib/contracts.ts together once after that deploy; later logic changes use Timelock upgrades (no address churn).

The full finding-by-finding reconciliation and test IDs live in [contracts/TEST_MATRIX.md](contracts/TEST_MATRIX.md).


Test & Audit Gate

No Monad deployment is ready until all gates pass:

cd contracts
forge test --offline

Current hardening baseline: 97 tests, 0 failures across token, attestation, feed, profile, achievements, staking, rewards, clubs, treasury, membership, badges, challenges, UUPS / Beacon / Multisig / Timelock upgrades, and privilege handoff.

Required pre-deploy checklist:

  • forge test passes with no compiler warnings.
  • Every High / Medium / Low finding in contracts/TEST_MATRIX.md is FIXED (Jul 18 2026 reaudits #1–#4).
  • Constructor and one-time wiring order matches the deployment flow below (DeployUpgradeableStack).
  • Frontend ABI/address constants and both env files match the UUPS cutover deployment.
  • Reward pools are funded without exceeding MovrToken.MAX_SUPPLY().
  • Representative reads confirm bytecode and expected configuration.
  • All new implementations are source-verified on MonadScan (proxies may remain bytecode-only; implementations verified).
  • Production trust policy is explicit: self-attest on, or trusted attester configured.
  • Production Multisig: set MULTISIG_THRESHOLD≥2 (hackathon uses threshold=1).

A green local suite validates the current source. It does not prove the addresses below run that bytecode.


Verified Monad Testnet Deployments

All addresses below are deployed on chain ID 10143, have non-empty bytecode, pass representative ABI read calls, and have source code verified on MonadScan. The frontend defaults in [src/lib/contracts.ts](src/lib/contracts.ts) and local overrides in .env.local must remain synchronized with this registry.

Jul 18 2026 UUPS cutover is live on the addresses below (Beacon + Multisig threshold=1 + Timelock 24h). Proxy addresses are stable — further logic changes use ./upgrade.sh (Multisig → Timelock), not redeploy. Token + Profile were kept. See contracts/TEST_MATRIX.md.

Contract Address Verified source
MovrMultisig 0x61Fc8DcD97Fb5f46489Ab2fBaBf6429Ed5ADA52B MonadScan
TimelockController 0xada899f2e96c31ca7e8De9e6f01e676a18fd67Ec MonadScan
Treasury Beacon 0x3efAf01Cd276ff8Db71F4fD04DB98ea02f88b59A MonadScan
MovrChainAttestation 0x8F31Cbb38b539cB9e3242E262bf40058904d739c MonadScan
MovrProfile 0x5079c9F03BafDaD54A4CBFdbf05662fdaC285832 MonadScan
MovrToken 0xD95C0f1F5F5F73e32F87B4f76d6a79809911B7BF MonadScan
AchievementNFT 0x1c5E27280a2D993CE3E8E8a19009488f0F38EB5A MonadScan
MovrStaking 0x762Ae6f37BC52CB0Ce81A6d4ad6c3b3B3658479d MonadScan
MovrClubRegistry 0x91cb9D4A5e14E5Ac0962E2d6cba963003A4EC9D3 MonadScan
ClubMemberNFT 0x9a3d2332E53e512DcFA65078884f5213aAfe2A0a MonadScan
ClubBadgeNFT 0xCC97214Be43c1A6E967caC448195FA3933C15764 MonadScan
MovrClubChallenges 0xB45d215FFb048D9477a9C4c6fA60b182B09538Ed MonadScan
MovrMilestoneReward 0x7B013C35E7bA65e51486C3f9005b6e19809CD270 MonadScan
MovrFeed 0xf6073E5A71D05336b6c260FA14f7a86520D403Aa MonadScan

Profile migration: 0xa16938B26824c3D2aACEb4e25a08937B7fCb202c is the retired pre-handle profile deployment. It does not implement setProfile(string,string,string,uint8) and must not be used by the frontend.

Upgrade Governance (UUPS + Timelock + Multisig)

Production major updates must not redeploy new addresses (that orphans runs, stakes, NFTs, and treasuries). Stateful contracts use:

Layer Role
ERC1967Proxy (UUPS) Stable address for Attestation, AchievementNFT, Staking, Registry, Member/Badge NFTs, Feed, MilestoneReward, Challenges
UpgradeableBeacon + BeaconProxy Shared ClubTreasury logic for every club
TimelockController (default 24h) Sole upgrade owner / admin
MovrMultisig (threshold 1–3, default 1 creator-only) Sole Timelock proposer / canceller / admin

MovrToken and MovrProfile remain non-upgradeable.

Propose an upgrade:

cd contracts

# See which proxies/beacon are configured
./upgrade.sh list

# ClubTreasury execute-manager fix (beacon — all clubs at once)
./upgrade.sh upgrade treasury

# Or any one UUPS proxy:
./upgrade.sh upgrade challenges
./upgrade.sh upgrade attestation

# Or every configured target:
./upgrade.sh upgrade all

Under the hood this deploys a new implementation, then runs UpgradeViaTimelock.s.sol.

  1. One Multisig signer runs ./upgrade.sh upgrade <name> (submits Timelock.schedule). With MULTISIG_THRESHOLD=1, the same tx also executes the Multisig call.
  2. If threshold is 2+, a second signer confirms + executes the Multisig transaction.
  3. Wait TIMELOCK_DELAY (default 86400s).
  4. ./upgrade.sh execute <name> (or EXECUTE_AFTER_DELAY=1 / Explorer).

Hackathon shortcut if the beacon/proxy is still owned by the deployer (before Timelock cutover):

./upgrade.sh direct treasury

Manual env form (same as the script):

TARGET=0xProxyOrBeacon NEW_IMPLEMENTATION=0xNewImpl MODE=uups \  # or MODE=beacon
MOVR_MULTISIG=0x... TIMELOCK=0x... \
  forge script script/UpgradeViaTimelock.s.sol:UpgradeViaTimelock \
  --rpc-url https://testnet-rpc.monad.xyz --broadcast --legacy

Storage layout is append-only (__gap reserved on each upgradeable contract). Never reorder or remove state variables in an upgrade.

Re-check bytecode and source verification

After the one-time proxy cutover, update contracts/.env, .env.local, and src/lib/contracts.ts once, then run:

cd contracts
./verify-all.sh

verify-all.sh submits Solidity Standard JSON to the Etherscan V2 API for Monad Testnet and prints a verified MonadScan link for each contract. It requires ETHERSCAN_API_KEY or MONADSCAN_API_KEY in contracts/.env.


Contract Deployment Guide (Monad Testnet)

Before running the deployment scripts, make sure you configure your local environment.

0. Mandatory preflight

cd contracts
forge test --offline

Stop if any test fails. The deployment scripts assume the same deployer controls the one-time registry, attestation, and NFT wiring calls.

1. Prerequisites & Environment Setup

  • Install Monad-compatible Foundry:
    foundryup --network monad
  • Change directory and copy environment template:
    cd contracts
    cp .env.example .env
  • Open contracts/.env and configure:
    • PRIVATE_KEY: Private key of a funded Monad Testnet deployer wallet (also Multisig signer 1).
    • MULTISIG_SIGNER_2 / MULTISIG_SIGNER_3: two additional distinct Multisig signers (required for ./redeploy-all.sh).
    • ADMIN_ADDRESS: Optional AchievementNFT admin — do not grant in the deploy script (would survive Timelock handoff). After cutover, Multisig→Timelock should call setAdmin(ADMIN_ADDRESS, true). Logged at deploy if set.
    • TIMELOCK_DELAY: Optional seconds (default 86400).
    • MOVR_TOKEN: existing token to keep.

To request gas money for deployment, visit the Monad Faucet.


2. Deploy Script Pipeline

The deployment scripts run using --gas-estimate-multiplier 250 and --slow options to account for Monad gas estimations and to avoid race conditions.

For a security-hardening rollout, use the dependency-ordered orchestrator:

./redeploy-all.sh

It deploys the upgradeable stack (DeployUpgradeableStack): Multisig + Timelock + UUPS proxies + ClubTreasury beacon, funds reward reserves, rewrites contracts/.env and root .env.local, and preserves MOVR_TOKEN / MOVR_PROFILE. After this cutover, do not redeploy to patch logic — use the Timelock upgrade path so addresses stay stable.

A. Core Stack (Token, Attestation, Achievements, Staking)

Runs deployment, registers default achievements, mints initial reward tokens, and funds the staking rewards pool:

./deploy.sh

Output prints contract addresses; populate MOVR_TOKEN, ATTESTATION, ACHIEVEMENT_NFT, and STAKING in contracts/.env.

B. Profile Registry

./deploy-profile.sh

Copy the emitted MOVR_PROFILE address to contracts/.env, and copy the emitted VITE_PROFILE_ADDRESS to the root .env.local and the baked fallback in src/lib/contracts.ts.

C. Clubs & Staking Link

Deploys ClubMemberNFT, MovrClubRegistry, ClubBadgeNFT, and staking; wires registry donations and club-badge boosts:

./deploy-clubs.sh

Output prints registry and member/badge NFT addresses; populate CLUB_REGISTRY in contracts/.env.

D. Club Challenges

./deploy-club-challenges.sh

E. Milestone Rewards & Pool Funding

Deploys the reward router, wires attestation.setClubRegistry(registry) for clubIdAtAttest, wires treasury rewards, approves the router, and funds the pool with 100,000 MOVR:

./deploy-milestone-reward.sh

F. Community Feed

./deploy-feed.sh

The feed constructor receives the deployer as owner so publication can be paused during moderation or incident response.

3. Required one-time wiring

The final deployment must satisfy:

ClubMemberNFT.MINTER_ROLE  → MovrClubRegistry
MovrStaking.clubRegistry   → MovrClubRegistry
MovrStaking.clubBadges     → ClubBadgeNFT
MovrClubRegistry.staking   → MovrStaking
MovrChainAttestation.clubRegistry → MovrClubRegistry
MovrMilestoneReward.clubRegistry  → MovrClubRegistry
MovrClubRegistry.milestoneReward  → MovrMilestoneReward
MovrClubRegistry.challenges       → MovrClubChallenges

For trusted production attestation:

grant ATTESTER_ROLE to verifier
setSelfAttestEnabled(false)

Do not disable self-attestation before the verifier is configured and tested.


Administrative & Operations Scripts

A set of shell scripts is available under contracts/ to manage, update, and audit active deployments.

Staking Pool Funding

To fund the MovrStaking reward pool with additional MOVR tokens (automatically mints more if owner balance is insufficient):

./fund-rewards.sh

Adjust reward quantity by overriding env variables: REWARD_AMOUNT=500000000000000000000000 ./fund-rewards.sh.

To refill the milestone claim pool (MovrMilestoneReward — pays 1 MOVR/km on verify). After Timelock handoff, a plain ERC20 transfer into the proxy is enough:

./fund-all-pools.sh          # top milestone to ≥1M MOVR now; schedule staking fund (Timelock)
./fund-all-pools.sh status
# after ~24h Timelock delay:
./fund-all-pools.sh execute  # completes staking fundRewards(1M)

Or milestone only: ./fund-milestone.sh / ./fund-all-pools.sh milestone-only.

If claim reverts with empty pool, the milestone contract’s MOVR balance is too low — run ./fund-all-pools.sh (or milestone-only), then retry claim (attest + publish can still succeed).

Checking Roles

Audit owner (DEFAULT_ADMIN_ROLE) and admin (ADMIN_ROLE) configurations on active contracts:

./check-role.sh                 # Inspects address defined in PRIVATE_KEY
./check-role.sh 0xYourAddress   # Inspects a specific address

Minting MOVR

Directly mint MOVR tokens to a target address:

./mint-movr.sh 10000000         # Mints 10,000,000 MOVR to the deployer wallet

Achievements Art & URI Updates

If achievement SVGs or metadata text have changed, you can update them without redeploying the core contracts:

  1. Re-generate SVGs and metadata files from the root of the project: npm run generate:art.
  2. Push updates to the contracts:
 # Redeploys AchievementNFT and Staking contracts with fresh data-URIs
 ./redeploy-nft-staking.sh

 # Incremental URI updates only (calls setAchievementURI)
 ./update-achievement-uris.sh

Source Verification

Verify every configured contract and print its MonadScan source link:

./verify-all.sh

The script reads deployed addresses and an Etherscan-compatible API key from contracts/.env. A successful submission must finish with Pass - Verified; bytecode presence alone is not source verification.


Monad Testnet Network Details

The application is optimized for the following network details:

  • Chain ID: 10143
  • RPC URL: https://testnet-rpc.monad.xyz
  • Currency Symbol: MON
  • Block Explorer: MonadScan Testnet

Gas Limit Considerations

Monad charges primarily on the transaction gas limit (not only gas used), so limits must be high enough to finish the write but not wildly oversized.

eth_estimateGas often undercounts cold storage and long string writes (feed publish, club proposals, achievement NFT mints that store data: token URIs on-chain). Observed claimAchievement estimates on testnet are ~3.1M gas for a typical metadata URI.

To avoid Out-Of-Gas (OOG) failures:

  • Deployment scripts use a 2.5× multiplier (--gas-estimate-multiplier 250).
  • Most frontend writes estimate then buffer (see [src/lib/monadGas.ts](src/lib/monadGas.ts) and VerifyClaim):
    • Achievement NFT claim: estimate × 1.5, floor 3,500,000
    • Club badge claim: estimate × 1.5, floor 400,000
    • Attestation: floor 350,000 (with estimate buffer in verify flow)
    • Feed publish: floor 800,000
    • Milestone reward claim: floor 550,000
  • Prefer estimate + modest buffer over a huge fixed limit: on Monad an oversized gas field costs real MON even if unused.
  • MonadScan may label a failed tx as “out of gas” when gasUsed == gasLimit; always check the decoded revert (e.g. not eligible) before assuming the floor alone was wrong.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages