Back to the sea X Buy $TIDE
Start · Introduction

Two seas, one lock.

Tidewell launches every token on Solana and Base a few seconds apart. The two markets price it on their own, so the same token ends up with two prices. We draw each price as a sea, put a lock between them, and let the higher side spill into the lower one.

What you are looking at

The home page is one scene. On the left is the Solana sea, on the right the Base sea, and the concrete column in the middle is the lock. Every glass buoy is a token. A buoy floating on both surfaces is trading on both chains. A buoy hanging on a tether is still flooding. A buoy lying sealed on the floor sits in the dry dock and has no price yet.

The water height on each side follows the selected token’s price on that chain. When the gap is big enough, the sluice opens and water arcs out of the lock into the lower sea. The giant number at the bottom of the hero is that gap.

Why two seas

Two chains never agree on a price for long. Bridges are slow, liquidity is split, and buyers on one side do not see the other. The gap is real money sitting in plain sight, and Tidewell is built to make it visible in one glance and claimable in one click.

NOTEThe home page runs a simulated tide until the $TIDE contract is set. Once it is, the buttons, the chart and the contract chip all switch to the real token.
Start · Quick start

Quick start

tidewell.js is a single ES module with no dependencies. Import it straight from the site, pass two addresses, and you get both prices, the gap and the spill back.

Read a tide

import { readTide } from "https://tidewellpad.vercel.app/lib/tidewell.js";

const tide = await readTide({
  solana: "So11111111111111111111111111111111111111112",
  base:   "0x4200000000000000000000000000000000000006"
});

console.log(tide.stage, tide.gap.pct.toFixed(2), tide.spill.from, "→", tide.spill.to);
# the same data tidewell.js reads, one sea at a time
curl -s https://api.dexscreener.com/tokens/v1/solana/So11111111111111111111111111111111111111112
curl -s https://api.dexscreener.com/tokens/v1/base/0x4200000000000000000000000000000000000006
<script type="module">
  import { watch, formatPrice } from "https://tidewellpad.vercel.app/lib/tidewell.js";
  watch({ solana: "<mint>", base: "<0x address>" }, (tide, err) => {
    if (err || !tide.gap) return;
    document.querySelector("#gap").textContent = "+" + tide.gap.pct.toFixed(2) + " %";
  });
</script>
<b id="gap">…</b>

The example pair above is wrapped SOL against wrapped ETH, so the gap is huge on purpose. Use the two addresses of one token on two chains and the number becomes the spread you can actually close.

Only the math

No network needed if you already have the prices.

JS
import { gap, spill } from "https://tidewellpad.vercel.app/lib/tidewell.js";

gap(0.0000131, 0.0000041).pct;          // 219.51
spill(0.0000131, 0.0000041, { names: ["solana", "base"] });
// { open: true, from: "solana", to: "base", grossPct: 219.51, netPct: 217.6, rate: 0.65 }
Mechanics · How it works

Two seas

One token, two markets, two prices. Everything else on Tidewell is a picture of that one fact.

The launch

A creator registers a token once. Tidewell gives it the same name and supply on both chains and opens trading on each sea when the creator says so, one sea first or both at once. From that moment the two markets drift apart, because the buyers on each side are different people with different wallets.

The lock

The lock is the column between the seas. It never lets the water mix on its own. The only way water crosses is through the sluice, and the sluice only opens when the gap is wider than the fees it costs to close it.

PieceOn the pageMeaning
Solana seaLeft, indigoThe token’s best USD price on Solana
Base seaRight, cobaltThe token’s best USD price on Base
LockConcrete column with two lampsKeeps the prices apart until someone closes the gap
SluiceAmber outlet with a pourThe direction and size of the gap
BuoyGlass sphere with a tickerOne token, drawn once per sea it trades on
Mechanics · Water levels

Water levels

The pricier sea stands taller against the lock. Height follows the ratio between the two prices on a log scale, so a 30 % gap and a 3000 % gap both stay on screen.

The formula

math
ratio = max(a, b) / min(a, b)
h     = min(1, ln(ratio) / ln(maxRise))     // maxRise = 6
high sea → +h,  low sea → −h,  equal → 0

With maxRise = 6 a token whose prices differ by +500 % or more draws at full height. On the home page full height is about six percent of the screen on each side, so the two surfaces never swallow the hero.

GapRatioHeight h
+1 %1.010.006
+30 %1.300.146
+100 %2.000.387
+219.5 %3.200.649
+500 % and up6.00+1.000
Mechanics · The spill

The spill

The spill is the gap, measured against the lower sea, minus what it costs to cross. If it is worth crossing, the sluice opens and pours from high to low.

Gross and net

math
gross = ratio − 1
net   = ratio × (1 − fee)² − 1             // fee = 0.003 per leg
open  = gross ≥ 0.01 and net > 0

The fee is paid twice: once to buy on the low sea, once to sell on the high sea. Below a 1 % gap the sluice stays shut and the scene shows two calm surfaces.

Direction

Water always pours from the high sea into the low one. The label above the sluice says where it goes, for example SLUICE → SOLANA, and the line under the big number repeats it as spills → Solana.

Claiming it

On the page, a click on the amber sluice claims the spill for a second: the pour bursts and the toast shows the gap you closed. On chain the same move is a buy on the low sea and a sell on the high sea, which pulls both prices toward each other.

WARNINGA gap can close before your second leg lands. Bridge time, block time and other people closing the same spill all eat into net. tidewell.js tells you the size of the gap; it does not trade for you.
Mechanics · Stages

Stages

Depth is state. The deeper a buoy sits, the earlier it is in its life. The gauge on the right edge of the home page reads the same three stages top to bottom.

StageWhereRule
openFloating on both surfacesTrading on both seas, has a gap
floodingMid-water, on a tetherOne or both seas armed, not trading on both yet
sealedDry dock on the sea floorRegistered, nothing armed, no price

The dry dock

Every token starts in the dry dock as a sealed buoy with a line across it. The dock is the dashed chamber at the bottom of the Solana sea, next to the lock. The counter above it shows how many are waiting.

Rising

When the creator floods the chamber, the buoy lifts off the floor and climbs on a tether. If only one sea is armed it rises on that side only. When it breaks the surface on both sides, two ripples spread and the token turns open.

JS
import { stage } from "https://tidewellpad.vercel.app/lib/tidewell.js";

stage({});                                             // "sealed"
stage({ armed: { solana: true } });                     // "flooding"
stage({ live: { solana: true, base: true } });          // "open"
Mechanics · Reading the scene

Reading the scene

Everything on the home page is clickable water. Here is what each click does.

You clickWhat happens
A buoyIt becomes the selected token. Both seas move to its prices, the big number shows its gap, and a card pops up with both prices and the direction.
The amber sluiceClaims the spill. The pour bursts and the toast shows the gap.
Open waterDrops a new sealed buoy into the dry dock with a fresh ticker. It floods on its own a little later.
A gauge labelDives to that depth: Open water, Flooding or Dry dock.

The ticker

The strip at the top lists every token that is open or flooding with both prices and the gap. It updates every second with the scene.

The gauge

The right edge shows how deep you are. Scrolling is diving: the camera moves down through the water column from the surface to the floor, and the amber reading shows the depth in metres.

Library · tidewell.js

tidewell.js

A small ES module that reads the tide between two chains. It is the same math the home page draws with, plus a reader for live prices from DexScreener.

Get it

import tide from "https://tidewellpad.vercel.app/lib/tidewell.js";
console.log(tide.VERSION);   // "0.3.1"
curl -sO https://tidewellpad.vercel.app/lib/tidewell.js
<script type="module" src="https://tidewellpad.vercel.app/lib/tidewell.js"></script>

What is inside

  • Math: gap, levels, spill, stage, formatPrice. Pure functions, no network.
  • Reader: price, readTide, watch. Fetch from the public DexScreener API, which allows browser requests.
  • Constants: SEAS, LOCK, VERSION, and the TideError class.

About 5 KB, no build step, works in any modern browser, Deno, Bun and Node 18+ (save it as .mjs for Node).

Library · API reference

API reference

Every export, what it takes and what it returns.

gap(a, b)

Returns { pct, ratio, high, level }. pct is measured against the lower price. high is "a", "b" or null. level is true when the gap is under 1 %.

levels(a, b, { maxRise })

Returns { a, b, gap } where a and b are heights in −1…1. See Water levels.

spill(a, b, { fee, minSpill, names })

Returns { open, from, to, grossPct, netPct, rate }. names labels the two sides, for example ["solana","base"]. rate is 0…1 and drives how hard the sluice pours.

stage({ armed, live })

Returns "sealed", "flooding" or "open".

price(chain, address, { fetch, api })

Async. Returns { chain, address, symbol, usd, liquidity, pair, url } for the most liquid pair where the token is the base side. Throws TideError.

readTide({ solana, base }, opts)

Async. Reads both seas in parallel and returns a tide object. A sea with no pair yet comes back as null, and the stage reads flooding.

watch(addrs, onTide, ms)

Polls readTide every ms (never faster than 5 s, default 15 s) and calls onTide(tide, err). Returns a stop() function.

JS
const stop = watch({ solana: mint, base: addr }, (tide, err) => {
  if (err) return console.warn(err.code, err.message);
  if (tide.spill?.open) console.log("spill", tide.spill.netPct.toFixed(2), "% →", tide.spill.to);
});
// later
stop();
Library · Try it

Try it

This block imports tidewell.js from this site and runs it in your browser. Type two prices and watch the lock, or read a live tide from two addresses.

From two prices

levels() + spill()—
…

From two addresses

Press the button. The defaults are wrapped SOL and wrapped ETH, so expect a silly gap.
Reference · Spec & formats

Spec & formats

Constants and the shape of a tide object.

Constants

NameValueWhat it does
LOCK.minSpill0.01Gaps under 1 % keep the sluice shut
LOCK.fee0.003Swap fee per leg, paid twice
LOCK.maxRise6Ratio that draws at full height
LOCK.pollMs15000Default interval for watch
LOCK.api…/tokens/v1DexScreener endpoint base
SEASsolana, baseKnown chains, keyed by DexScreener chainId

Tide object

JSON
{
  "seas": {
    "solana": { "symbol": "TIDE", "usd": 0.0000131, "liquidity": 41200, "pair": "…", "url": "…" },
    "base":   { "symbol": "TIDE", "usd": 0.0000041, "liquidity": 18800, "pair": "…", "url": "…" }
  },
  "stage": "open",
  "gap":    { "pct": 219.51, "ratio": 3.195, "high": "a", "level": false },
  "spill":  { "open": true, "from": "solana", "to": "base", "grossPct": 219.51, "netPct": 217.6, "rate": 0.648 },
  "levels": { "solana": 0.649, "base": -0.649 },
  "at": "2026-10-29T18:22:45.594Z"
}
Reference · Errors

Errors

Everything tidewell.js throws is a TideError with a short code.

CodeWhenWhat to do
E_PRICEA price is zero, negative or not a numberCheck the input, prices must be positive
E_SEAUnknown chain nameUse solana or base
E_ADDRMissing addressPass at least one of { solana, base }
E_DRYNo priced pair on that chain yetreadTide turns this into null and stage flooding
E_RATEDexScreener answered 429Poll slower, 15 s is plenty
E_HTTPAny other non-OK answerRetry later
Reference · Limits & threat model

Limits

A gap on screen is not money in your wallet yet. Here is what stands between them.

Time

The two legs land on two chains with different block times. If you move funds across a bridge between legs, the gap can be gone when you arrive. Holding inventory on both seas is the only way to close a spill in one move.

Depth

A thin pool moves the moment you trade in it. The liquidity field in each sea tells you how deep it is; a 300 % gap in a pool with a few hundred dollars is a puddle, not a sea.

Look-alikes

Anyone can deploy a token with the same name on another chain. Always compare addresses, never tickers. tidewell.js matches pairs by the exact token address and ignores everything else.

Data

Prices come from DexScreener and can lag a few seconds behind the chain. The home page shows a simulated tide until the $TIDE contract is set.

Token · $TIDE

$TIDE

The token of the lock itself. It is the big amber buoy on the home page, the one selected when you arrive.

Ticker$TIDE
Contractsoon
BuyBuy $TIDE
ChartOpen the chart
XTidewell on X

The buttons go live the moment the contract is published. Until then they stay where they are and wait, like everything else in the dry dock.

Token · FAQ

FAQ

Why is the number so big?

Because fresh tokens on two chains really do sit that far apart for the first minutes. The gap shrinks as people close it. Small gaps mean the lock is doing its job.

Which way does the water go?

From the pricier sea into the cheaper one. The label on the sluice and the line under the big number both say it.

Can I use tidewell.js for any token?

Yes, if it trades on Solana and Base and DexScreener sees the pairs. Pass its two addresses to readTide.

Does clicking the water launch a real token?

No. On the home page a click drops a sealed buoy into the dry dock so you can watch the life cycle. Real launches go through the creator flow.

Where is the contract?

On the $TIDE page and in the chip at the top of the home page, as soon as it is published.