first commit
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: sp-currency-provider-binance
|
||||
description: Binance public-ticker crypto-rates provider implementing the CurrencyProvider contract for @suaveplan/currency.
|
||||
---
|
||||
|
||||
# Binance Currency Provider for Suaveplan
|
||||
|
||||
Binance public-ticker crypto-rates provider that implements the `CurrencyProvider`
|
||||
contract from `@suaveplan/currency` on top of the slim `@suaveplan/currency-providers`
|
||||
core. Fetches from Binance's free, key-less `/api/v3/ticker/price` endpoint and
|
||||
returns inverted spot mid-prices (`1 / price`) ready for `CurrencyConverter`.
|
||||
|
||||
## Architecture
|
||||
|
||||
| Component | Responsibility |
|
||||
|-----------|---------------|
|
||||
| `BinanceProvider` | Main class implementing `CurrencyProvider`; fetches ticker data, decodes rates, and returns `RateFetchResult` |
|
||||
| `BINANCE_PROVIDER_NAME` | Stable identifier constant (`"binance"`) used as registry key and `provider.name` |
|
||||
| `BINANCE_DEFAULT_BASE_URL` | Default REST base URL (`"https://api.binance.com/api/v3"`) overridable via constructor |
|
||||
| `ensureTickerArray` | Validates the upstream JSON payload is an array of `{ symbol: string; price: string }` rows; throws `UPSTREAM_ERROR` on mismatch |
|
||||
| `decodeRates` | Parses ticker rows, filters by base suffix (`endsWith`), inverts prices (`1 / price`), and silently skips zero/negative/non-finite prices |
|
||||
| `filterTargets` | When `options.targets` is provided, restricts the rate map to requested currencies and throws `UNKNOWN_CURRENCY` for any missing target |
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
money/finance/currency-provider-binance/
|
||||
src/binance/binance.ts # BinanceProvider class, constants, and internal helpers
|
||||
src/binance/index.ts # Barrel re-exporting the binance module
|
||||
src/index.ts # Root barrel re-exporting from binance/
|
||||
```
|
||||
|
||||
Sibling packages:
|
||||
- `@suaveplan/currency` — universal currency conversion engine (`CurrencyConverter`, `RateCache`, `CurrencyProvider` interface)
|
||||
- `@suaveplan/currency-providers` — slim core providing `CurrencyProviderRegistry`, `httpRequest`, `CurrencyProviderError`, and shared config types (`NoKeyConfig`, `ApiKeyConfig`)
|
||||
- `@suaveplan/currency-provider-ecb` — fiat provider sibling using the European Central Bank daily rates
|
||||
- `@suaveplan/currency-provider-coingecko` — crypto provider sibling using CoinGecko's API
|
||||
|
||||
## Patterns
|
||||
|
||||
### Quick Start
|
||||
|
||||
```typescript
|
||||
import { CurrencyConverter } from "@suaveplan/currency";
|
||||
import { BinanceProvider } from "@suaveplan/currency-provider-binance";
|
||||
|
||||
const provider = new BinanceProvider();
|
||||
const converter = new CurrencyConverter({
|
||||
provider,
|
||||
staleDurationMs: 30_000,
|
||||
});
|
||||
|
||||
const rate = await converter.getRate("USDT", "BTC");
|
||||
```
|
||||
|
||||
### Registry Registration
|
||||
|
||||
```typescript
|
||||
import { CurrencyProviderRegistry } from "@suaveplan/currency-providers";
|
||||
import { BinanceProvider, BINANCE_PROVIDER_NAME } from "@suaveplan/currency-provider-binance";
|
||||
|
||||
const registry = new CurrencyProviderRegistry();
|
||||
registry.register(new BinanceProvider());
|
||||
|
||||
const result = await registry
|
||||
.get(BINANCE_PROVIDER_NAME)
|
||||
.fetchRates({ base: "USDT", targets: ["BTC", "ETH", "SOL"] });
|
||||
```
|
||||
|
||||
### Injectable Fetch for Testing or Proxies
|
||||
|
||||
```typescript
|
||||
import type { FetchLike } from "@suaveplan/types";
|
||||
|
||||
const proxiedFetch: FetchLike = async (url, init) => {
|
||||
return await fetch(`https://proxy.example.com/${String(url)}`, init);
|
||||
};
|
||||
|
||||
const binance = new BinanceProvider({
|
||||
fetch: proxiedFetch,
|
||||
baseUrl: "https://api.binance.com/api/v3",
|
||||
timeoutMs: 8_000,
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Base Suffix
|
||||
|
||||
```typescript
|
||||
const provider = new BinanceProvider();
|
||||
|
||||
// Fetch EUR-quoted pairs instead of the default USDT
|
||||
const result = await provider.fetchRates({ base: "EUR" });
|
||||
// result.rates.BTC === 1 / 62000 (from BTC/EUR ticker)
|
||||
```
|
||||
|
||||
## Constraints
|
||||
|
||||
- `supportsCrypto === true`, `supportsFiat === false` — this provider only covers crypto assets listed on Binance spot markets
|
||||
- No API key required; the provider uses Binance's public `/api/v3/ticker/price` endpoint
|
||||
- Rates are stored as `1 / price` so the result answers "1 unit of base = N units of asset"
|
||||
- Zero, negative, and non-finite ticker prices are silently skipped (not surfaced as errors) to handle delisted-but-published symbols
|
||||
- When `options.targets` is provided, any target absent from the upstream listing raises `UNKNOWN_CURRENCY` instead of being omitted
|
||||
- Symbols whose entire name equals the base suffix (e.g. `USDTUSDT`) are defensively skipped to avoid empty-string rate keys
|
||||
- Transport errors (non-2xx) are raised as `CurrencyProviderError` with code `HTTP_ERROR` by the shared `httpRequest` helper
|
||||
|
||||
## Checklist
|
||||
|
||||
1. Import from `@suaveplan/currency-provider-binance` for the root barrel, or `@suaveplan/currency-provider-binance/binance/binance` for the subpath export
|
||||
2. Pass an injectable `FetchLike` in the constructor when testing or proxying
|
||||
3. Use `targets` to restrict the returned rate map and surface missing pairs as typed errors
|
||||
4. Remember prices are inverted (`1 / price`) — expect small numbers for expensive assets
|
||||
5. Verify `provider.supportsFiat` is `false` before using this provider for fiat conversions
|
||||
Reference in New Issue
Block a user