October 28, 2026

Introducing the cNGN rate picker

 Introducing the cNGN rate picker
Share Post:

A market can stop trading and still keep reporting its last price as though nothing had changed. Anyone reading that number has no way of telling, from the number alone, that it is months old. cngn-rate-picker is built with that risk in mind.

cngn-rate-picker is an open source TypeScript library, hosted by the WrappedCBDC organisation on GitHub. It works out USDT to naira and USDC to naira rates: what one unit of a dollar stablecoin is worth in naira. It draws on several sources at once rather than depending on a single one.

Why one naira price feed is not enough

Naira stablecoin markets can be thin. In a thin market, one large trade or a lopsided order book can push the quoted price away from where the market is really trading. A market that has stopped trading can also keep serving its last price. The library's own documentation records exactly this for at least one market.

Either problem can put a wrong number into a real transaction. With only one feed, there is nothing to compare it against.

Every source, every request

cngn-rate-picker queries every eligible source you have configured on every request. "Eligible" means every source except one that has been paused after repeated failures, covered below. Nothing stops early because the first source answered.

That helps in two ways:

  • Resilience. If a source is down or times out, the others can still supply a rate.

  • Visibility. Every successful quote comes back in the response, tagged to show whether it fed the final rate. You can see what each source was saying at the moment you asked.

What is a time-weighted average price (TWAP)?

Much of the library's handling of prices rests on one idea: the time-weighted average price, or TWAP.

A TWAP averages a price over a stretch of time, so a price that stood for longer counts for more than one that appeared briefly. In this library, each observation is weighted by how long it stood as the most recent one.

An illustration with made-up numbers: a market sits at 1,395 naira for the first 50 minutes of an hour, then moves to 1,410 for the last 10. The time-weighted average is 1,397.5. A "latest price" reading at the end of that hour would say 1,410.

Two points of clarity:

  • TWAP here is not a trading strategy. Traders use TWAP to split a large order into small pieces spread evenly over time. cngn-rate-picker places no orders. It uses time-weighting only to arrive at a reference rate.

  • TWAP is not VWAP. A volume-weighted average price (VWAP) weights each price by how much traded at it. TWAP ignores volume and considers only how long a price stood. It softens an unusual price rather than removing it: one that persists still counts, in proportion to how long it lasted.

Two kinds of averaging

The library applies time-weighting in two places: inside each source, and across sources.

1. Inside each source. Where a source has price history, it quotes the time-weighted average over the last hour by default, rather than the newest price. In a thin market, this limits how far one unusual trade can pull the quote. Each built-in source handles it in its own way:

  • Exchange trade history: quotes the 1-hour TWAP of completed trades. If nothing traded in that hour, it falls back to the order book by default.

  • Exchange candles: quotes the 1-hour TWAP of each short candle's closing price.

  • Wallet provider: exposes only a current rate for each route, so the library averages across routes.

  • Peer-to-peer listings: these are standing offers, not completed trades. The source filters out advertisers below its reputation thresholds and prices far from the median, then quotes the midpoint of the most common buy and sell prices.

The window length, and the option to use the latest price instead, are both configurable. The README documents the method for every built-in source.

2. Across sources, if you choose. By default, you get the price from your highest-priority source that succeeded. To average several, raise a setting called threshold. Set threshold to 3, for example, and the library averages your top three sources that answered, in priority order. Each quote is weighted by how long it stood as the latest answer before the next one arrived. Every source is queried either way; threshold only decides how many feed the final number.

Failing safely

Two guards handle sources that misbehave:

  • Cooldown. If a source keeps failing, the library stops calling it for a cooldown period, then tries it again.

  • Staleness guard. The built-in source that reads exchange candle data refuses a price whose data has gone stale beyond a set limit, six hours by default. The picker then moves on to the other sources. The limit can be changed or switched off.

The staleness guard exists for the problem at the top of this piece. The README's reasoning is that a months-old number averaged into a rate is worse than no quote at all. In both cases, the library sets the source aside instead of using it.

Built for more than one stablecoin

USDT and USDC are supported out of the box. Other dollar-backed stablecoins can be added without a library update, as long as your sources quote a market for them. Whether a given source lists a market for a given coin varies, and the README notes cases where it does not.

Each stablecoin gets its own picker. A picker rejects, at construction, any source that declares a different coin, which keeps quotes for different coins out of the same average. The one exception is a source that declares a plain "USD" fiat proxy, which every picker accepts; no built-in source does. If you need both USDT and USDC rates, create two pickers.

Does cngn-rate-picker set the cNGN price?

No. cngn-rate-picker does not set or maintain the peg of Compliant Naira (cNGN) to the naira. What it does is narrower.

A product that moves between cNGN and a dollar stablecoin may need to know what that dollar stablecoin is worth in naira at the moment of the transaction. The library works that out from the sources you configure, using time-weighted averages where history exists. It returns every source's quote alongside the final rate, so the inputs can be inspected. If no source can supply a rate, it throws an error instead of returning one.

Use it, read it, change if needed.

cngn-rate-picker is open source under the MIT licence. Anyone can use it, inspect how it works, or contribute to it. According to the README, new sources are the most common contribution, and it carries a checklist for adding one. To report a bug or propose a change, open an issue on the repository.

Full documentation, the built-in sources and the code: https://github.com/wrappedcbdc/cngn-rate-picker

Frequently asked questions

1. How do I get the USDT to naira rate in TypeScript? Add cngn-rate-picker to your project, create a picker for USDT, add your sources in priority order and request a rate. The README on GitHub walks through setup with examples.

2. Which stablecoins does cngn-rate-picker support? USDT and USDC out of the box. Other dollar-backed stablecoins can be added without a library update, as long as your sources quote a market for them.

3. What happens if every source fails? The library throws an error instead of returning a rate, so a missing price never slips quietly into a transaction.

4. Is cngn-rate-picker free to use? Yes. It is open source under the MIT licence.

USDT and USDC are third-party stablecoins. cNGN is not affiliated with their issuers.