@beluswap/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,292 @@
1
+ # BeluSwap SDK
2
+
3
+ Human-friendly TypeScript SDK for BeluSwap concentrated liquidity AMM on Stellar.
4
+
5
+ ## Why BeluSwap SDK?
6
+
7
+ **No more manual conversions!** Use normal numbers instead of:
8
+ - ❌ Converting amounts to stroops (7 decimals)
9
+ - ❌ Calculating sqrt_price_x64 in Q64.64 format
10
+ - ❌ Converting prices to ticks
11
+ - ❌ Aligning ticks to spacing
12
+ - ❌ Converting days to ledgers
13
+ - ❌ Converting percentages to basis points
14
+
15
+ ✅ **Just use human-readable inputs!**
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @beluswap/sdk
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```typescript
26
+ import BeluSwapSDK from '@beluswap/sdk';
27
+
28
+ // Initialize SDK
29
+ const sdk = new BeluSwapSDK({
30
+ factoryAddress: 'CFACTORY...',
31
+ network: 'testnet', // or 'mainnet'
32
+ });
33
+
34
+ // Create pool with NORMAL numbers!
35
+ const pool = await sdk.factory.createPool({
36
+ creator: 'GCREATOR...',
37
+ tokenA: 'CDUSDC...',
38
+ tokenB: 'CDXLM...',
39
+ feeTier: 'VOLATILE', // Not 30 bps!
40
+ creatorFeePercent: 1, // 1%, not 100 bps!
41
+ initialPrice: 1.0, // Normal price!
42
+ amount0: 100, // 100 tokens, not stroops!
43
+ amount1: 100,
44
+ priceRangeLower: 0.95, // Normal price range!
45
+ priceRangeUpper: 1.05,
46
+ lockDurationDays: 7, // Days, not ledgers!
47
+ });
48
+
49
+ console.log(pool.summary);
50
+ // {
51
+ // pair: "CDUSDC.../CDXLM...",
52
+ // fee: "0.3%",
53
+ // initialPrice: 1,
54
+ // priceRange: "0.95 - 1.05",
55
+ // amounts: "100 + 100",
56
+ // lockDuration: "7 days"
57
+ // }
58
+ ```
59
+
60
+ ## Features
61
+
62
+ ### ✅ Human-Friendly Inputs
63
+ - Normal prices (1.0, 2.5) instead of sqrt_price_x64
64
+ - Normal amounts (100, 500) instead of stroops
65
+ - Percentages (1% slippage) instead of basis points
66
+ - Days for lock duration instead of ledgers
67
+ - Fee tier names ('VOLATILE') instead of numbers
68
+
69
+ ### ✅ Complete Integration
70
+ - **Factory SDK**: Create pools
71
+ - **Pool SDK**: Add/remove liquidity, swap, collect fees
72
+ - **Automatic Conversions**: All technical formats handled
73
+
74
+ ### ✅ Type-Safe
75
+ - Full TypeScript support
76
+ - Autocomplete for all parameters
77
+ - Compile-time error checking
78
+
79
+ ## Usage Examples
80
+
81
+ ### 1. Initialize SDK
82
+
83
+ ```typescript
84
+ import BeluSwapSDK from '@beluswap/sdk';
85
+
86
+ // Option A: Use predefined network
87
+ const sdk = new BeluSwapSDK({
88
+ factoryAddress: 'CFACTORY...',
89
+ network: 'testnet', // or 'mainnet'
90
+ });
91
+
92
+ // Option B: Custom network
93
+ const sdk = new BeluSwapSDK({
94
+ factoryAddress: 'CFACTORY...',
95
+ rpcUrl: 'https://your-rpc-url',
96
+ networkPassphrase: 'Your Network ; Passphrase',
97
+ });
98
+ ```
99
+
100
+ ### 2. Add Liquidity
101
+
102
+ ```typescript
103
+ // Connect to pool
104
+ const pool = await sdk.getAndConnectPool({
105
+ tokenA: 'CDUSDC...',
106
+ tokenB: 'CDXLM...',
107
+ feeTier: 'VOLATILE',
108
+ });
109
+
110
+ // Add liquidity with normal numbers!
111
+ const addLiq = await pool.addLiquidity({
112
+ owner: 'GOWNER...',
113
+ amount0: 50, // 50 tokens!
114
+ amount1: 50,
115
+ priceRangeLower: 0.95, // Normal prices!
116
+ priceRangeUpper: 1.05,
117
+ feeTier: 'VOLATILE',
118
+ });
119
+
120
+ console.log(addLiq.summary);
121
+ // { priceRange: "0.9500 - 1.0500", amounts: "50 + 50" }
122
+ ```
123
+
124
+ ### 3. Execute Swap
125
+
126
+ ```typescript
127
+ const swap = await pool.swap({
128
+ sender: 'GTRADER...',
129
+ tokenIn: 'USDC',
130
+ amountIn: 10, // Normal amount!
131
+ slippagePercent: 1, // 1%, not 100 bps!
132
+ priceLimit: 0.95, // Optional
133
+ });
134
+
135
+ console.log(swap.summary);
136
+ // {
137
+ // swapping: "10 USDC",
138
+ // estimatedOutput: "~9.9700",
139
+ // minimumOutput: "9.9003",
140
+ // slippage: "1%"
141
+ // }
142
+ ```
143
+
144
+ ### 4. Check Position
145
+
146
+ ```typescript
147
+ const position = await pool.getPosition({
148
+ owner: 'GOWNER...',
149
+ priceRangeLower: 0.95,
150
+ priceRangeUpper: 1.05,
151
+ feeTier: 'VOLATILE',
152
+ });
153
+
154
+ console.log(position);
155
+ // {
156
+ // amount0: 100, // Human-readable!
157
+ // amount1: 100,
158
+ // feesOwed0: 0.5,
159
+ // feesOwed1: 0.5
160
+ // }
161
+ ```
162
+
163
+ ## API Reference
164
+
165
+ ### BeluSwapSDK
166
+
167
+ Main SDK class.
168
+
169
+ #### Constructor
170
+
171
+ ```typescript
172
+ new BeluSwapSDK(config: {
173
+ factoryAddress: string;
174
+ poolAddress?: string;
175
+ network?: 'testnet' | 'mainnet';
176
+ rpcUrl?: string;
177
+ networkPassphrase?: string;
178
+ })
179
+ ```
180
+
181
+ #### Properties
182
+
183
+ - `factory: BelugaFactorySDK` - Factory operations
184
+ - `pool?: BelugaPoolSDK` - Pool operations (if connected)
185
+
186
+ #### Methods
187
+
188
+ - `connectPool(address: string): BelugaPoolSDK` - Connect to specific pool
189
+ - `getAndConnectPool(params): Promise<BelugaPoolSDK>` - Get and connect pool
190
+
191
+ ---
192
+
193
+ ### BelugaFactorySDK
194
+
195
+ Factory operations for pool creation.
196
+
197
+ #### Methods
198
+
199
+ ##### `createPool(params): Promise<CreatePoolResult>`
200
+
201
+ Create a new pool.
202
+
203
+ **Parameters:**
204
+ - `creator: string` - Creator address
205
+ - `tokenA: string` - Token A address
206
+ - `tokenB: string` - Token B address
207
+ - `feeTier: 'STABLE' | 'VOLATILE' | 'EXOTIC'` - Fee tier
208
+ - `creatorFeePercent: number` - Creator fee (0.1-10%)
209
+ - `initialPrice: number` - Initial price
210
+ - `amount0: number` - Initial token0 amount
211
+ - `amount1: number` - Initial token1 amount
212
+ - `priceRangeLower: number` - Lower price bound
213
+ - `priceRangeUpper: number` - Upper price bound
214
+ - `lockDurationDays?: number` - Lock duration in days
215
+ - `permanent?: boolean` - Permanent lock?
216
+
217
+ **Returns:** Object with `summary`, `contractParams`, and `technical` details.
218
+
219
+ ##### `getPool(params): Promise<string | null>`
220
+
221
+ Get pool address.
222
+
223
+ ##### `poolExists(params): Promise<boolean>`
224
+
225
+ Check if pool exists.
226
+
227
+ ---
228
+
229
+ ### BelugaPoolSDK
230
+
231
+ Pool operations for liquidity and swaps.
232
+
233
+ #### Methods
234
+
235
+ ##### `addLiquidity(params): Promise<AddLiquidityResult>`
236
+
237
+ Add liquidity to pool.
238
+
239
+ ##### `removeLiquidity(params)`
240
+
241
+ Remove liquidity from pool.
242
+
243
+ ##### `swap(params): Promise<SwapResult>`
244
+
245
+ Execute a swap.
246
+
247
+ ##### `previewSwap(params): Promise<PreviewSwapResult>`
248
+
249
+ Preview swap output (read-only, no gas).
250
+
251
+ ##### `getPosition(params): Promise<PositionInfo>`
252
+
253
+ Get position information.
254
+
255
+ ##### `collectFees(params)`
256
+
257
+ Collect accumulated fees.
258
+
259
+ ##### `getPoolState(): Promise<PoolState>`
260
+
261
+ Get current pool state.
262
+
263
+ ---
264
+
265
+ ## Fee Tiers
266
+
267
+ Three predefined fee tiers:
268
+
269
+ | Tier | Fee | Tick Spacing | Use Case |
270
+ |------|-----|--------------|----------|
271
+ | STABLE | 0.05% | 10 | Stablecoin pairs |
272
+ | VOLATILE | 0.30% | 60 | Normal volatile pairs |
273
+ | EXOTIC | 1.00% | 200 | Exotic/meme tokens |
274
+
275
+ ## Examples
276
+
277
+ See [examples/](examples/) directory for complete examples:
278
+ - `create-pool.ts` - Create a new pool
279
+ - `add-liquidity.ts` - Add liquidity to pool
280
+ - `swap.ts` - Execute swaps
281
+ - `monitor-position.ts` - Monitor position value
282
+
283
+
284
+ ## License
285
+
286
+ Apache 2.0
287
+
288
+ ## Support
289
+
290
+ - GitHub Issues: [github.com/Beluga-Swap/sdk/issues](https://github.com/Beluga-Swap/sdk/issues)
291
+ - Discord: [discord.gg/belugaswap](https://discord.gg/belugaswap)
292
+ - Email: support@beluswap.io
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@beluswap/sdk",
3
+ "version": "0.1.0",
4
+ "description": "BelugaSwap TypeScript SDK with human-friendly inputs",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "src",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "build:watch": "tsc --watch",
16
+ "clean": "rm -rf dist",
17
+ "prepublish": "npm run clean && npm run build",
18
+ "test": "jest",
19
+ "lint": "eslint src --ext .ts",
20
+ "format": "prettier --write \"src/**/*.ts\""
21
+ },
22
+ "keywords": [
23
+ "belugaswap",
24
+ "stellar",
25
+ "soroban",
26
+ "dex",
27
+ "amm",
28
+ "concentrated-liquidity",
29
+ "sdk",
30
+ "typescript"
31
+ ],
32
+ "author": "BelugaSwap Team",
33
+ "license": "Apache-2.0",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/Beluga-Swap/sdk.git"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/Beluga-Swap/sdk/issues"
40
+ },
41
+ "homepage": "https://github.com/Beluga-Swap/sdk#readme",
42
+ "dependencies": {
43
+ "@stellar/stellar-sdk": "^12.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^20.0.0",
47
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
48
+ "@typescript-eslint/parser": "^6.0.0",
49
+ "eslint": "^8.0.0",
50
+ "jest": "^29.0.0",
51
+ "prettier": "^3.0.0",
52
+ "typescript": "^5.0.0"
53
+ },
54
+ "engines": {
55
+ "node": ">=18.0.0"
56
+ }
57
+ }
package/src/config.ts ADDED
@@ -0,0 +1,82 @@
1
+ // src/config.ts
2
+ // BelugaSwap SDK Configuration
3
+
4
+ /**
5
+ * SDK Configuration Constants
6
+ */
7
+ export const BELUGA_CONFIG = {
8
+ // Stellar stroops (7 decimals)
9
+ STROOPS_DECIMALS: 7,
10
+ STROOPS_MULTIPLIER: 10_000_000,
11
+
12
+ // Q64.64 format
13
+ Q64: BigInt(2) ** BigInt(64),
14
+ ONE_X64: BigInt(2) ** BigInt(64), // 18446744073709551616
15
+
16
+ // Tick constants
17
+ MIN_TICK: -887272,
18
+ MAX_TICK: 887272,
19
+ TICK_BASE: 1.0001,
20
+
21
+ // Fee tiers
22
+ FEE_TIERS: {
23
+ STABLE: {
24
+ name: 'STABLE' as const,
25
+ bps: 5,
26
+ spacing: 10,
27
+ percent: 0.05,
28
+ description: 'For stablecoin pairs (0.05% fee)',
29
+ },
30
+ VOLATILE: {
31
+ name: 'VOLATILE' as const,
32
+ bps: 30,
33
+ spacing: 60,
34
+ percent: 0.30,
35
+ description: 'For volatile pairs (0.30% fee)',
36
+ },
37
+ EXOTIC: {
38
+ name: 'EXOTIC' as const,
39
+ bps: 100,
40
+ spacing: 200,
41
+ percent: 1.00,
42
+ description: 'For exotic/meme pairs (1.00% fee)',
43
+ },
44
+ },
45
+
46
+ // Validation limits
47
+ MIN_LOCK_DURATION_LEDGERS: 120_960, // ~7 days
48
+ MIN_INITIAL_LIQUIDITY: 1_000_000, // 0.1 tokens
49
+ MIN_CREATOR_FEE_BPS: 10, // 0.1%
50
+ MAX_CREATOR_FEE_BPS: 1000, // 10%
51
+ MAX_SLIPPAGE_BPS: 5000, // 50%
52
+ } as const;
53
+
54
+ /**
55
+ * Fee tier type
56
+ */
57
+ export type FeeTier = keyof typeof BELUGA_CONFIG.FEE_TIERS;
58
+
59
+ /**
60
+ * Network configuration
61
+ */
62
+ export interface NetworkConfig {
63
+ rpcUrl: string;
64
+ networkPassphrase: string;
65
+ name?: string;
66
+ }
67
+
68
+ /**
69
+ * Predefined networks
70
+ */
71
+ export const NETWORKS = {
72
+ TESTNET: {
73
+ rpcUrl: 'https://soroban-testnet.stellar.org',
74
+ networkPassphrase: 'Test SDF Network ; September 2015',
75
+ name: 'Testnet',
76
+ },
77
+ MAINNET: {
78
+ rpcUrl: 'https://soroban-mainnet.stellar.org',
79
+ networkPassphrase: 'Public Global Stellar Network ; September 2015',
80
+ name: 'Mainnet',
81
+ },
82
+ } as const;
@@ -0,0 +1,153 @@
1
+ // src/converters.ts
2
+ // Core conversion utilities
3
+
4
+ import { BELUGA_CONFIG } from './config';
5
+
6
+ /**
7
+ * Price Converters
8
+ */
9
+ export class PriceConverter {
10
+ /**
11
+ * Convert human price to sqrt_price_x64
12
+ */
13
+ static toSqrtPrice(price: number): bigint {
14
+ if (price <= 0) throw new Error("Price must be positive");
15
+ const sqrtPrice = Math.sqrt(price);
16
+ return BigInt(Math.floor(sqrtPrice * Number(BELUGA_CONFIG.Q64)));
17
+ }
18
+
19
+ /**
20
+ * Convert sqrt_price_x64 to human price
21
+ */
22
+ static fromSqrtPrice(sqrtPriceX64: bigint): number {
23
+ const sqrtPrice = Number(sqrtPriceX64) / Number(BELUGA_CONFIG.Q64);
24
+ return sqrtPrice * sqrtPrice;
25
+ }
26
+
27
+ /**
28
+ * Format price for display
29
+ */
30
+ static format(sqrtPriceX64: bigint, decimals: number = 6): string {
31
+ const price = this.fromSqrtPrice(sqrtPriceX64);
32
+ return price.toFixed(decimals);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Tick Converters
38
+ */
39
+ export class TickConverter {
40
+ /**
41
+ * Convert human price to tick
42
+ */
43
+ static priceToTick(price: number): number {
44
+ if (price <= 0) throw new Error("Price must be positive");
45
+ return Math.floor(Math.log(price) / Math.log(BELUGA_CONFIG.TICK_BASE));
46
+ }
47
+
48
+ /**
49
+ * Convert tick to human price
50
+ */
51
+ static tickToPrice(tick: number): number {
52
+ return Math.pow(BELUGA_CONFIG.TICK_BASE, tick);
53
+ }
54
+
55
+ /**
56
+ * Align tick to spacing
57
+ */
58
+ static align(tick: number, spacing: number): number {
59
+ return Math.floor(tick / spacing) * spacing;
60
+ }
61
+
62
+ /**
63
+ * Create tick range from price range
64
+ */
65
+ static createRange(
66
+ lowerPrice: number,
67
+ upperPrice: number,
68
+ spacing: number
69
+ ): { lowerTick: number; upperTick: number } {
70
+ return {
71
+ lowerTick: this.align(this.priceToTick(lowerPrice), spacing),
72
+ upperTick: this.align(this.priceToTick(upperPrice), spacing),
73
+ };
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Amount Converters (Stroops ↔ Human)
79
+ */
80
+ export class AmountConverter {
81
+ /**
82
+ * Convert human amount to stroops
83
+ */
84
+ static toStroops(amount: number): bigint {
85
+ return BigInt(Math.floor(amount * BELUGA_CONFIG.STROOPS_MULTIPLIER));
86
+ }
87
+
88
+ /**
89
+ * Convert stroops to human amount
90
+ */
91
+ static fromStroops(stroops: bigint | number): number {
92
+ const stroopsNum = typeof stroops === 'bigint' ? Number(stroops) : stroops;
93
+ return stroopsNum / BELUGA_CONFIG.STROOPS_MULTIPLIER;
94
+ }
95
+
96
+ /**
97
+ * Format amount for display
98
+ */
99
+ static format(stroops: bigint | number, decimals: number = 7): string {
100
+ const amount = this.fromStroops(stroops);
101
+ return amount.toFixed(decimals);
102
+ }
103
+
104
+ /**
105
+ * Format with token symbol
106
+ */
107
+ static formatWithSymbol(
108
+ stroops: bigint | number,
109
+ symbol: string,
110
+ decimals: number = 7
111
+ ): string {
112
+ return `${this.format(stroops, decimals)} ${symbol}`;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Fee Converters
118
+ */
119
+ export class FeeConverter {
120
+ /**
121
+ * Convert percent to basis points
122
+ */
123
+ static percentToBps(percent: number): number {
124
+ return Math.floor(percent * 100);
125
+ }
126
+
127
+ /**
128
+ * Convert basis points to percent
129
+ */
130
+ static bpsToPercent(bps: number): number {
131
+ return bps / 100;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Time Converters
137
+ */
138
+ export class TimeConverter {
139
+ /**
140
+ * Convert days to ledgers
141
+ */
142
+ static daysToLedgers(days: number): number {
143
+ // 1 day ≈ 17,280 ledgers (5s per ledger)
144
+ return Math.floor(days * 17_280);
145
+ }
146
+
147
+ /**
148
+ * Convert ledgers to days
149
+ */
150
+ static ledgersToDays(ledgers: number): number {
151
+ return ledgers / 17_280;
152
+ }
153
+ }
package/src/factory.ts ADDED
@@ -0,0 +1,151 @@
1
+ // src/factory.ts
2
+ // Factory SDK for pool creation
3
+
4
+ import { Contract, SorobanRpc } from '@stellar/stellar-sdk';
5
+ import { BELUGA_CONFIG } from './config';
6
+ import { PriceConverter, TickConverter, AmountConverter, FeeConverter, TimeConverter } from './converters';
7
+ import type { CreatePoolParams, CreatePoolResult, GetPoolParams } from './types';
8
+
9
+ /**
10
+ * BelugaSwap Factory SDK
11
+ * Create pools with human-friendly inputs
12
+ */
13
+ export class BelugaFactorySDK {
14
+ private contract: Contract;
15
+
16
+ constructor(
17
+ private contractId: string,
18
+ private rpc: SorobanRpc.Server,
19
+ private networkPassphrase: string
20
+ ) {
21
+ this.contract = new Contract(contractId);
22
+ }
23
+
24
+ /**
25
+ * Create a new pool with human-friendly inputs
26
+ */
27
+ async createPool(params: CreatePoolParams): Promise<CreatePoolResult> {
28
+ // 1. Get fee tier info
29
+ const feeTier = BELUGA_CONFIG.FEE_TIERS[params.feeTier];
30
+ const feeBps = feeTier.bps;
31
+ const tickSpacing = feeTier.spacing;
32
+
33
+ // 2. Convert creator fee
34
+ const creatorFeeBps = FeeConverter.percentToBps(params.creatorFeePercent);
35
+ if (creatorFeeBps < BELUGA_CONFIG.MIN_CREATOR_FEE_BPS ||
36
+ creatorFeeBps > BELUGA_CONFIG.MAX_CREATOR_FEE_BPS) {
37
+ throw new Error("Creator fee must be between 0.1% and 10%");
38
+ }
39
+
40
+ // 3. Convert initial price
41
+ const initialSqrtPrice = PriceConverter.toSqrtPrice(params.initialPrice);
42
+ const currentTick = TickConverter.priceToTick(params.initialPrice);
43
+
44
+ // 4. Convert amounts to stroops
45
+ const amount0Stroops = AmountConverter.toStroops(params.amount0);
46
+ const amount1Stroops = AmountConverter.toStroops(params.amount1);
47
+
48
+ // Validate minimum
49
+ if (amount0Stroops < BELUGA_CONFIG.MIN_INITIAL_LIQUIDITY ||
50
+ amount1Stroops < BELUGA_CONFIG.MIN_INITIAL_LIQUIDITY) {
51
+ throw new Error("Minimum amount is 0.1 tokens each");
52
+ }
53
+
54
+ // 5. Convert price range to ticks
55
+ const range = TickConverter.createRange(
56
+ params.priceRangeLower,
57
+ params.priceRangeUpper,
58
+ tickSpacing
59
+ );
60
+
61
+ if (range.lowerTick >= range.upperTick) {
62
+ throw new Error("Lower price must be less than upper price");
63
+ }
64
+
65
+ // 6. Convert lock duration
66
+ let lockDuration: number;
67
+ if (params.permanent) {
68
+ lockDuration = 0;
69
+ } else if (params.lockDurationDays) {
70
+ lockDuration = TimeConverter.daysToLedgers(params.lockDurationDays);
71
+ if (lockDuration < BELUGA_CONFIG.MIN_LOCK_DURATION_LEDGERS) {
72
+ throw new Error("Minimum lock duration is 7 days");
73
+ }
74
+ } else {
75
+ lockDuration = BELUGA_CONFIG.MIN_LOCK_DURATION_LEDGERS;
76
+ }
77
+
78
+ // 7. Prepare contract params
79
+ const contractParams = {
80
+ creator: params.creator,
81
+ params: {
82
+ token_a: params.tokenA,
83
+ token_b: params.tokenB,
84
+ fee_bps: feeBps,
85
+ creator_fee_bps: creatorFeeBps,
86
+ initial_sqrt_price_x64: initialSqrtPrice.toString(),
87
+ amount0_desired: amount0Stroops.toString(),
88
+ amount1_desired: amount1Stroops.toString(),
89
+ lower_tick: range.lowerTick,
90
+ upper_tick: range.upperTick,
91
+ lock_duration: lockDuration,
92
+ }
93
+ };
94
+
95
+ // 8. Return result
96
+ return {
97
+ summary: {
98
+ pair: `${params.tokenA}/${params.tokenB}`,
99
+ fee: `${feeTier.percent}%`,
100
+ creatorFee: `${params.creatorFeePercent}%`,
101
+ initialPrice: params.initialPrice,
102
+ priceRange: `${params.priceRangeLower} - ${params.priceRangeUpper}`,
103
+ amounts: `${params.amount0} + ${params.amount1}`,
104
+ lockDuration: params.permanent
105
+ ? 'Permanent'
106
+ : `${params.lockDurationDays} days`,
107
+ },
108
+ contractParams,
109
+ technical: {
110
+ feeBps,
111
+ creatorFeeBps,
112
+ sqrtPriceX64: initialSqrtPrice.toString(),
113
+ currentTick,
114
+ tickSpacing,
115
+ lowerTick: range.lowerTick,
116
+ upperTick: range.upperTick,
117
+ amount0Stroops: amount0Stroops.toString(),
118
+ amount1Stroops: amount1Stroops.toString(),
119
+ lockDurationLedgers: lockDuration,
120
+ },
121
+ };
122
+ }
123
+
124
+ /**
125
+ * Get pool address
126
+ */
127
+ async getPool(params: GetPoolParams): Promise<string | null> {
128
+ const feeBps = BELUGA_CONFIG.FEE_TIERS[params.feeTier].bps;
129
+
130
+ // TODO: Implement contract call
131
+ // const result = await this.contract.call('get_pool_address', ...);
132
+
133
+ throw new Error("Not implemented - add contract integration");
134
+ }
135
+
136
+ /**
137
+ * Check if pool exists
138
+ */
139
+ async poolExists(params: GetPoolParams): Promise<boolean> {
140
+ const pool = await this.getPool(params);
141
+ return pool !== null;
142
+ }
143
+
144
+ /**
145
+ * Get total number of pools
146
+ */
147
+ async getTotalPools(): Promise<number> {
148
+ // TODO: Implement contract call
149
+ throw new Error("Not implemented - add contract integration");
150
+ }
151
+ }
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ // BelugaSwap SDK - Main Export
2
+ // Version: 0.1.0
3
+
4
+ export { BelugaSwapSDK as default, BelugaSwapSDK } from './sdk';
5
+ export { BelugaFactorySDK } from './factory';
6
+ export { BelugaPoolSDK } from './pool';
7
+ export { BELUGA_CONFIG } from './config';
8
+ export * from './types';
9
+ export * from './converters';
10
+
11
+ // Re-export for convenience
12
+ import { BelugaSwapSDK } from './sdk';
13
+ export default BelugaSwapSDK;
package/src/pool.ts ADDED
@@ -0,0 +1,265 @@
1
+ // src/pool.ts
2
+ // Pool SDK for liquidity and swap operations
3
+
4
+ import { Contract, SorobanRpc } from '@stellar/stellar-sdk';
5
+ import { BELUGA_CONFIG } from './config';
6
+ import { PriceConverter, TickConverter, AmountConverter } from './converters';
7
+ import type {
8
+ AddLiquidityParams,
9
+ AddLiquidityResult,
10
+ RemoveLiquidityParams,
11
+ SwapParams,
12
+ SwapResult,
13
+ PreviewSwapResult,
14
+ GetPositionParams,
15
+ PositionInfo,
16
+ CollectFeesParams,
17
+ PoolState,
18
+ } from './types';
19
+
20
+ /**
21
+ * BelugaSwap Pool SDK
22
+ * Interact with pools using human-friendly inputs
23
+ */
24
+ export class BelugaPoolSDK {
25
+ private contract: Contract;
26
+
27
+ constructor(
28
+ private contractId: string,
29
+ private rpc: SorobanRpc.Server,
30
+ private networkPassphrase: string
31
+ ) {
32
+ this.contract = new Contract(contractId);
33
+ }
34
+
35
+ /**
36
+ * Add liquidity with human-friendly inputs
37
+ */
38
+ async addLiquidity(params: AddLiquidityParams): Promise<AddLiquidityResult> {
39
+ // 1. Get tick spacing
40
+ const tickSpacing = BELUGA_CONFIG.FEE_TIERS[params.feeTier].spacing;
41
+
42
+ // 2. Convert price range to ticks
43
+ const range = TickConverter.createRange(
44
+ params.priceRangeLower,
45
+ params.priceRangeUpper,
46
+ tickSpacing
47
+ );
48
+
49
+ // 3. Convert amounts to stroops
50
+ const amount0Stroops = AmountConverter.toStroops(params.amount0);
51
+ const amount1Stroops = AmountConverter.toStroops(params.amount1);
52
+
53
+ // 4. Prepare contract params
54
+ const contractParams = {
55
+ owner: params.owner,
56
+ lower_tick: range.lowerTick,
57
+ upper_tick: range.upperTick,
58
+ amount0_desired: amount0Stroops.toString(),
59
+ amount1_desired: amount1Stroops.toString(),
60
+ };
61
+
62
+ return {
63
+ summary: {
64
+ priceRange: `${params.priceRangeLower.toFixed(4)} - ${params.priceRangeUpper.toFixed(4)}`,
65
+ amounts: `${params.amount0} + ${params.amount1}`,
66
+ },
67
+ contractParams,
68
+ technical: {
69
+ lowerTick: range.lowerTick,
70
+ upperTick: range.upperTick,
71
+ tickSpacing,
72
+ amount0Stroops: amount0Stroops.toString(),
73
+ amount1Stroops: amount1Stroops.toString(),
74
+ }
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Remove liquidity with human-friendly inputs
80
+ */
81
+ async removeLiquidity(params: RemoveLiquidityParams) {
82
+ if (params.liquidityPercent <= 0 || params.liquidityPercent > 100) {
83
+ throw new Error("Liquidity percent must be between 0 and 100");
84
+ }
85
+
86
+ const tickSpacing = BELUGA_CONFIG.FEE_TIERS[params.feeTier].spacing;
87
+ const range = TickConverter.createRange(
88
+ params.priceRangeLower,
89
+ params.priceRangeUpper,
90
+ tickSpacing
91
+ );
92
+
93
+ return {
94
+ summary: {
95
+ removing: `${params.liquidityPercent}% of liquidity`,
96
+ priceRange: `${params.priceRangeLower} - ${params.priceRangeUpper}`,
97
+ },
98
+ contractParams: {
99
+ owner: params.owner,
100
+ lower_tick: range.lowerTick,
101
+ upper_tick: range.upperTick,
102
+ },
103
+ technical: {
104
+ lowerTick: range.lowerTick,
105
+ upperTick: range.upperTick,
106
+ percentToRemove: params.liquidityPercent,
107
+ }
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Execute swap with human-friendly inputs
113
+ */
114
+ async swap(params: SwapParams): Promise<SwapResult> {
115
+ // 1. Convert amount to stroops
116
+ const amountInStroops = AmountConverter.toStroops(params.amountIn);
117
+
118
+ // 2. Calculate slippage in bps
119
+ const slippageBps = Math.floor(params.slippagePercent * 100);
120
+ if (slippageBps > BELUGA_CONFIG.MAX_SLIPPAGE_BPS) {
121
+ throw new Error("Slippage cannot exceed 50%");
122
+ }
123
+
124
+ // 3. Estimate output (placeholder - should call preview_swap)
125
+ const currentPrice = 1.0; // TODO: Get from pool state
126
+ const estimatedOut = params.amountIn * currentPrice;
127
+ const minAmountOut = estimatedOut * (1 - params.slippagePercent / 100);
128
+ const minAmountOutStroops = AmountConverter.toStroops(minAmountOut);
129
+
130
+ // 4. Convert price limit
131
+ const sqrtPriceLimitX64 = params.priceLimit
132
+ ? PriceConverter.toSqrtPrice(params.priceLimit)
133
+ : BigInt(0);
134
+
135
+ // 5. Prepare contract params
136
+ const contractParams = {
137
+ sender: params.sender,
138
+ token_in: params.tokenIn,
139
+ amount_in: amountInStroops.toString(),
140
+ amount_out_min: minAmountOutStroops.toString(),
141
+ sqrt_price_limit_x64: sqrtPriceLimitX64.toString(),
142
+ };
143
+
144
+ return {
145
+ summary: {
146
+ swapping: `${params.amountIn} ${params.tokenIn}`,
147
+ estimatedOutput: `~${estimatedOut.toFixed(4)}`,
148
+ minimumOutput: `${minAmountOut.toFixed(4)}`,
149
+ slippage: `${params.slippagePercent}%`,
150
+ priceLimit: params.priceLimit ? `${params.priceLimit}` : 'None',
151
+ },
152
+ contractParams,
153
+ technical: {
154
+ amountInStroops: amountInStroops.toString(),
155
+ minAmountOutStroops: minAmountOutStroops.toString(),
156
+ slippageBps,
157
+ sqrtPriceLimitX64: sqrtPriceLimitX64.toString(),
158
+ }
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Preview swap output (read-only)
164
+ */
165
+ async previewSwap(params: {
166
+ tokenIn: string;
167
+ amountIn: number;
168
+ }): Promise<PreviewSwapResult> {
169
+ const amountInStroops = AmountConverter.toStroops(params.amountIn);
170
+
171
+ // TODO: Call contract preview_swap
172
+
173
+ // Placeholder
174
+ return {
175
+ amountOut: params.amountIn * 0.997,
176
+ priceImpact: 0.3,
177
+ newPrice: 1.003,
178
+ };
179
+ }
180
+
181
+ /**
182
+ * Get position info (human-readable)
183
+ */
184
+ async getPosition(params: GetPositionParams): Promise<PositionInfo> {
185
+ const tickSpacing = BELUGA_CONFIG.FEE_TIERS[params.feeTier].spacing;
186
+ const range = TickConverter.createRange(
187
+ params.priceRangeLower,
188
+ params.priceRangeUpper,
189
+ tickSpacing
190
+ );
191
+
192
+ // TODO: Call contract get_position
193
+
194
+ // Mock result
195
+ const result = {
196
+ liquidity: 10000000,
197
+ amount0: BigInt(50_000_000),
198
+ amount1: BigInt(50_000_000),
199
+ fees_owed_0: BigInt(500_000),
200
+ fees_owed_1: BigInt(500_000),
201
+ };
202
+
203
+ return {
204
+ liquidity: result.liquidity,
205
+ amount0: AmountConverter.fromStroops(result.amount0),
206
+ amount1: AmountConverter.fromStroops(result.amount1),
207
+ feesOwed0: AmountConverter.fromStroops(result.fees_owed_0),
208
+ feesOwed1: AmountConverter.fromStroops(result.fees_owed_1),
209
+ formatted: {
210
+ liquidity: result.liquidity.toLocaleString(),
211
+ amounts: `${AmountConverter.fromStroops(result.amount0)} + ${AmountConverter.fromStroops(result.amount1)}`,
212
+ fees: `${AmountConverter.fromStroops(result.fees_owed_0)} + ${AmountConverter.fromStroops(result.fees_owed_1)}`,
213
+ }
214
+ };
215
+ }
216
+
217
+ /**
218
+ * Collect fees
219
+ */
220
+ async collectFees(params: CollectFeesParams) {
221
+ const tickSpacing = BELUGA_CONFIG.FEE_TIERS[params.feeTier].spacing;
222
+ const range = TickConverter.createRange(
223
+ params.priceRangeLower,
224
+ params.priceRangeUpper,
225
+ tickSpacing
226
+ );
227
+
228
+ return {
229
+ contractParams: {
230
+ owner: params.owner,
231
+ lower_tick: range.lowerTick,
232
+ upper_tick: range.upperTick,
233
+ },
234
+ technical: {
235
+ lowerTick: range.lowerTick,
236
+ upperTick: range.upperTick,
237
+ }
238
+ };
239
+ }
240
+
241
+ /**
242
+ * Get current pool state (human-readable)
243
+ */
244
+ async getPoolState(): Promise<PoolState> {
245
+ // TODO: Call contract get_pool_state
246
+
247
+ // Mock state
248
+ const state = {
249
+ sqrt_price_x64: (BigInt(1) << BigInt(64)).toString(),
250
+ current_tick: 0,
251
+ liquidity: 100_000_000,
252
+ };
253
+
254
+ return {
255
+ currentPrice: PriceConverter.fromSqrtPrice(BigInt(state.sqrt_price_x64)),
256
+ currentTick: state.current_tick,
257
+ liquidity: state.liquidity,
258
+ technical: {
259
+ sqrtPriceX64: state.sqrt_price_x64,
260
+ currentTick: state.current_tick,
261
+ liquidity: state.liquidity,
262
+ }
263
+ };
264
+ }
265
+ }
package/src/sdk.ts ADDED
@@ -0,0 +1,110 @@
1
+ // src/sdk.ts
2
+ // Main SDK class combining Factory and Pool
3
+
4
+ import { SorobanRpc } from '@stellar/stellar-sdk';
5
+ import { BelugaFactorySDK } from './factory';
6
+ import { BelugaPoolSDK } from './pool';
7
+ import { NETWORKS } from './config';
8
+ import type { NetworkConfig } from './config';
9
+
10
+ /**
11
+ * SDK Configuration
12
+ */
13
+ export interface BelugaSDKConfig {
14
+ factoryAddress: string;
15
+ poolAddress?: string;
16
+ rpcUrl?: string;
17
+ networkPassphrase?: string;
18
+ network?: 'testnet' | 'mainnet';
19
+ }
20
+
21
+ /**
22
+ * Main BelugaSwap SDK
23
+ * Complete integration from Factory to Pool operations
24
+ */
25
+ export class BelugaSwapSDK {
26
+ public factory: BelugaFactorySDK;
27
+ public pool?: BelugaPoolSDK;
28
+ private rpc: SorobanRpc.Server;
29
+ private networkPassphrase: string;
30
+
31
+ constructor(config: BelugaSDKConfig) {
32
+ // Determine network configuration
33
+ let networkConfig: NetworkConfig;
34
+
35
+ if (config.network) {
36
+ // Use predefined network
37
+ networkConfig = NETWORKS[config.network.toUpperCase() as keyof typeof NETWORKS];
38
+ } else if (config.rpcUrl && config.networkPassphrase) {
39
+ // Use custom network
40
+ networkConfig = {
41
+ rpcUrl: config.rpcUrl,
42
+ networkPassphrase: config.networkPassphrase,
43
+ };
44
+ } else {
45
+ throw new Error(
46
+ 'Must provide either "network" (testnet/mainnet) or both "rpcUrl" and "networkPassphrase"'
47
+ );
48
+ }
49
+
50
+ this.rpc = new SorobanRpc.Server(networkConfig.rpcUrl);
51
+ this.networkPassphrase = networkConfig.networkPassphrase;
52
+
53
+ // Initialize factory
54
+ this.factory = new BelugaFactorySDK(
55
+ config.factoryAddress,
56
+ this.rpc,
57
+ this.networkPassphrase
58
+ );
59
+
60
+ // Initialize pool if address provided
61
+ if (config.poolAddress) {
62
+ this.pool = new BelugaPoolSDK(
63
+ config.poolAddress,
64
+ this.rpc,
65
+ this.networkPassphrase
66
+ );
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Connect to a specific pool
72
+ */
73
+ connectPool(poolAddress: string): BelugaPoolSDK {
74
+ this.pool = new BelugaPoolSDK(
75
+ poolAddress,
76
+ this.rpc,
77
+ this.networkPassphrase
78
+ );
79
+ return this.pool;
80
+ }
81
+
82
+ /**
83
+ * Get pool address and connect in one step
84
+ */
85
+ async getAndConnectPool(params: {
86
+ tokenA: string;
87
+ tokenB: string;
88
+ feeTier: 'STABLE' | 'VOLATILE' | 'EXOTIC';
89
+ }): Promise<BelugaPoolSDK> {
90
+ const poolAddress = await this.factory.getPool(params);
91
+ if (!poolAddress) {
92
+ throw new Error('Pool does not exist');
93
+ }
94
+ return this.connectPool(poolAddress);
95
+ }
96
+
97
+ /**
98
+ * Get RPC server instance
99
+ */
100
+ getRpc(): SorobanRpc.Server {
101
+ return this.rpc;
102
+ }
103
+
104
+ /**
105
+ * Get network passphrase
106
+ */
107
+ getNetworkPassphrase(): string {
108
+ return this.networkPassphrase;
109
+ }
110
+ }
package/src/types.ts ADDED
@@ -0,0 +1,202 @@
1
+ // src/types.ts
2
+ // TypeScript type definitions
3
+
4
+ import { FeeTier } from './config';
5
+
6
+ /**
7
+ * Pool Creation Parameters
8
+ */
9
+ export interface CreatePoolParams {
10
+ creator: string;
11
+ tokenA: string;
12
+ tokenB: string;
13
+ feeTier: FeeTier;
14
+ creatorFeePercent: number;
15
+ initialPrice: number;
16
+ amount0: number;
17
+ amount1: number;
18
+ priceRangeLower: number;
19
+ priceRangeUpper: number;
20
+ lockDurationDays?: number;
21
+ permanent?: boolean;
22
+ }
23
+
24
+ /**
25
+ * Pool Creation Result
26
+ */
27
+ export interface CreatePoolResult {
28
+ summary: {
29
+ pair: string;
30
+ fee: string;
31
+ creatorFee: string;
32
+ initialPrice: number;
33
+ priceRange: string;
34
+ amounts: string;
35
+ lockDuration: string;
36
+ };
37
+ contractParams: any;
38
+ technical: {
39
+ feeBps: number;
40
+ creatorFeeBps: number;
41
+ sqrtPriceX64: string;
42
+ currentTick: number;
43
+ tickSpacing: number;
44
+ lowerTick: number;
45
+ upperTick: number;
46
+ amount0Stroops: string;
47
+ amount1Stroops: string;
48
+ lockDurationLedgers: number;
49
+ };
50
+ }
51
+
52
+ /**
53
+ * Add Liquidity Parameters
54
+ */
55
+ export interface AddLiquidityParams {
56
+ owner: string;
57
+ amount0: number;
58
+ amount1: number;
59
+ priceRangeLower: number;
60
+ priceRangeUpper: number;
61
+ feeTier: FeeTier;
62
+ }
63
+
64
+ /**
65
+ * Add Liquidity Result
66
+ */
67
+ export interface AddLiquidityResult {
68
+ summary: {
69
+ priceRange: string;
70
+ amounts: string;
71
+ };
72
+ contractParams: {
73
+ owner: string;
74
+ lower_tick: number;
75
+ upper_tick: number;
76
+ amount0_desired: string;
77
+ amount1_desired: string;
78
+ };
79
+ technical: {
80
+ lowerTick: number;
81
+ upperTick: number;
82
+ tickSpacing: number;
83
+ amount0Stroops: string;
84
+ amount1Stroops: string;
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Remove Liquidity Parameters
90
+ */
91
+ export interface RemoveLiquidityParams {
92
+ owner: string;
93
+ liquidityPercent: number;
94
+ priceRangeLower: number;
95
+ priceRangeUpper: number;
96
+ feeTier: FeeTier;
97
+ }
98
+
99
+ /**
100
+ * Swap Parameters
101
+ */
102
+ export interface SwapParams {
103
+ sender: string;
104
+ tokenIn: string;
105
+ amountIn: number;
106
+ slippagePercent: number;
107
+ priceLimit?: number;
108
+ }
109
+
110
+ /**
111
+ * Swap Result
112
+ */
113
+ export interface SwapResult {
114
+ summary: {
115
+ swapping: string;
116
+ estimatedOutput: string;
117
+ minimumOutput: string;
118
+ slippage: string;
119
+ priceLimit: string;
120
+ };
121
+ contractParams: {
122
+ sender: string;
123
+ token_in: string;
124
+ amount_in: string;
125
+ amount_out_min: string;
126
+ sqrt_price_limit_x64: string;
127
+ };
128
+ technical: {
129
+ amountInStroops: string;
130
+ minAmountOutStroops: string;
131
+ slippageBps: number;
132
+ sqrtPriceLimitX64: string;
133
+ };
134
+ }
135
+
136
+ /**
137
+ * Preview Swap Result
138
+ */
139
+ export interface PreviewSwapResult {
140
+ amountOut: number;
141
+ priceImpact: number;
142
+ newPrice: number;
143
+ }
144
+
145
+ /**
146
+ * Position Info
147
+ */
148
+ export interface PositionInfo {
149
+ liquidity: number;
150
+ amount0: number;
151
+ amount1: number;
152
+ feesOwed0: number;
153
+ feesOwed1: number;
154
+ formatted: {
155
+ liquidity: string;
156
+ amounts: string;
157
+ fees: string;
158
+ };
159
+ }
160
+
161
+ /**
162
+ * Pool State
163
+ */
164
+ export interface PoolState {
165
+ currentPrice: number;
166
+ currentTick: number;
167
+ liquidity: number;
168
+ technical: {
169
+ sqrtPriceX64: string;
170
+ currentTick: number;
171
+ liquidity: number;
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Get Position Parameters
177
+ */
178
+ export interface GetPositionParams {
179
+ owner: string;
180
+ priceRangeLower: number;
181
+ priceRangeUpper: number;
182
+ feeTier: FeeTier;
183
+ }
184
+
185
+ /**
186
+ * Collect Fees Parameters
187
+ */
188
+ export interface CollectFeesParams {
189
+ owner: string;
190
+ priceRangeLower: number;
191
+ priceRangeUpper: number;
192
+ feeTier: FeeTier;
193
+ }
194
+
195
+ /**
196
+ * Get Pool Parameters
197
+ */
198
+ export interface GetPoolParams {
199
+ tokenA: string;
200
+ tokenB: string;
201
+ feeTier: FeeTier;
202
+ }