Syntropy
A liquidity layer between cash and the blockchain.
Created on 8th March 2026
β’
Syntropy
A liquidity layer between cash and the blockchain.
The problem Syntropy solves
Imagine this.
You just landed in a small town for a family wedding. Your phone has βΉ50,000 in UPI. But the local flower vendor only takes cash. The nearest ATM? 12 kilometers away, and it's been "out of service" for three days. The bank branch closes in 20 minutes and has a line out the door. Your digital wallet is full, but your hands are empty.
This isn't a rare edge case. This is daily life for millions.
- π§ ATM deserts β India shut down 30,000+ ATMs between 2020β2024. Rural areas lost them the fastest
- π Network failures β UPI outages, server downtime, bank maintenance windows β when digital rails go down, there's no backup
- πΈ Cash-dependent economies β street vendors, auto drivers, local markets, temple donations β cash is still the default
- π Not just India β emerging markets across Southeast Asia, Africa, and Latin America face the same liquidity gap
The root cause isn't technology failure. It's infrastructure centralization. Every cash access point β ATMs, bank branches, payment kiosks β is owned by a single entity that decides where to deploy, when to refill, and who gets access.
What if cash access wasn't controlled by institutions at all?
What if the shop next door, the chai stall at the corner, the pharmacy down the street could become your ATM β converting your digital money to cash on the spot, trustlessly, with no middleman?
That's SYNTROPY.
Challenges we ran into
1. MetaMask Transactions Failing Silently on Polygon Amoy
The first time I tried creating an on-chain escrow from the frontend, MetaMask would pop up, I'd confirm, and then⦠nothing. No error, no revert, just a hung transaction. Turns out Polygon Amoy's RPC endpoints don't support
eth_maxPriorityFeePerGas
, which ethers.js v6 calls by default for EIP-1559 transactions. MetaMask would silently fail trying to estimate gas.Fix: I forced legacy (Type 0) transactions by manually setting
gasPrice
instead ofmaxFeePerGas
+maxPriorityFeePerGas
. I also added a 30 gwei floor to prevent underpriced transactions. This one took hours to debug because the error surfaced deep inside MetaMask's internal RPC layer, not in my code.2. Leaflet + Next.js SSR Crash
Leaflet requires
window
anddocument
to exist β but Next.js renders on the server first where neither exists. Every time I imported Leaflet normally, the build would crash withReferenceError: window is not defined
.Fix: I wrapped every react-leaflet component (
MapContainer
,TileLayer
,Marker
,Circle
,Popup
) innext/dynamic
with{ ssr: false }
. For custom icons, I addedtypeof window === "undefined"
guards and lazy-required Leaflet inside those functions. It's not the cleanest pattern, but it works reliably.3. Wallet Connection Flow β Race Conditions
The auth flow involves 4 sequential async steps: connect MetaMask β fetch nonce from backend β
personal_sign
the nonce β POST signature to verify. During testing, I kept hitting a bug where the nonce stored in the DB didn't match the one being signed. The issue was that rapid button clicks would fire multiple nonce requests, and the second one would overwrite the first in the database before the first signature was verified.Fix: I added an upsert (
ON CONFLICT DO UPDATE
) for wallet sessions so the latest nonce always wins, and restructured the frontendlogin()
function to be a single sequentialuseCallback
chain that can't be double-invoked.4. Database Unreachable During Demo
During a live demo run, Supabase had a brief connectivity hiccup and the entire node discovery flow broke β the map showed zero nodes. For a hackathon demo, that's a death sentence.
Fix: I added a
MOCK_NODES
fallback array with 5 seed nodes around Kolkata. When the PostgreSQL query fails, the backend gracefully degrades to serving mock data with asource: "mock"
flag so the frontend still works. Same thing forgetAllNodes
β if the DB is down, mock data keeps the demo alive.5. Environment Variables Silently Missing in Production
After deploying the frontend to Vercel, every single API call returned a network error. The app looked perfect but was completely non-functional. Spent 30 minutes before I realized
NEXT_PUBLIC_BACKEND_URL
wasn't set in Vercel's env config, so all fetch calls were hittinglocalhost:5000
on Vercel's servers.Fix: I added runtime warnings that fire in the browser console when
NEXT_PUBLIC_BACKEND_URL
orNEXT_PUBLIC_ROUTING_ENGINE_URL
aren't set and the hostname isn'tlocalhost
. It's a small thing, but it would've saved me a lot of time.6. Solidity Contract Size Limit
The
Escrow.sol
contract kept hitting the 24KB Spurious Dragon bytecode limit when I tried combining escrow + reputation + insurance logic into one contract. The deployment would just fail with a cryptic "exceeds contract size limit" error.Fix: I split the system into 4 separate contracts (
Escrow
,NodeRegistry
,InsurancePool
,Reputation
) with cross-contract references. I also set Hardhat's optimizer toruns: 1
(minimize bytecode at the cost of slightly higher gas per call) β a worthwhile tradeoff since deployment cost on a testnet matters more than per-call savings.Tracks Applied (1)
