pumpswap-python-sdk 1.0.0__py3-none-any.whl

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.
@@ -0,0 +1,273 @@
1
+ """
2
+ Utility functions for mathematical calculations and conversions
3
+ """
4
+
5
+ import math
6
+ from typing import Tuple, Optional
7
+ from solders.pubkey import Pubkey
8
+ from ..constants import BASIS_POINTS, LAMPORTS_PER_SOL
9
+ from ..types.amm_types import PoolReserves, GlobalConfig
10
+
11
+
12
+ def ceil_div(a: int, b: int) -> int:
13
+ """
14
+ Ceiling division - ensures no precision loss in token calculations
15
+
16
+ Args:
17
+ a: Dividend
18
+ b: Divisor
19
+
20
+ Returns:
21
+ Ceiling of a/b
22
+ """
23
+ if b == 0:
24
+ raise ValueError("Division by zero")
25
+ return (a + b - 1) // b
26
+
27
+
28
+ def floor_div(a: int, b: int) -> int:
29
+ """
30
+ Floor division for token calculations
31
+
32
+ Args:
33
+ a: Dividend
34
+ b: Divisor
35
+
36
+ Returns:
37
+ Floor of a/b
38
+ """
39
+ if b == 0:
40
+ raise ValueError("Division by zero")
41
+ return a // b
42
+
43
+
44
+ def fee(amount: int, basis_points: int) -> int:
45
+ """
46
+ Calculate fee amount from basis points
47
+
48
+ Args:
49
+ amount: Amount to calculate fee on
50
+ basis_points: Fee in basis points (1 bps = 0.01%)
51
+
52
+ Returns:
53
+ Fee amount
54
+ """
55
+ return ceil_div(amount * basis_points, BASIS_POINTS)
56
+
57
+
58
+ def apply_slippage(amount: int, slippage_bps: int, is_maximum: bool = True) -> int:
59
+ """
60
+ Apply slippage to an amount
61
+
62
+ Args:
63
+ amount: Base amount
64
+ slippage_bps: Slippage in basis points
65
+ is_maximum: True for maximum amount (adds slippage), False for minimum (subtracts)
66
+
67
+ Returns:
68
+ Amount with slippage applied
69
+ """
70
+ slippage_amount = fee(amount, slippage_bps)
71
+
72
+ if is_maximum:
73
+ return amount + slippage_amount
74
+ else:
75
+ return max(0, amount - slippage_amount)
76
+
77
+
78
+ def pool_market_cap(
79
+ supply: int,
80
+ base_reserve: int,
81
+ quote_reserve: int,
82
+ decimals: int = 6
83
+ ) -> int:
84
+ """
85
+ Calculate pool market cap based on current reserves and token supply
86
+
87
+ Args:
88
+ supply: Total token supply
89
+ base_reserve: Base token reserve in pool
90
+ quote_reserve: Quote token reserve in pool
91
+ decimals: Token decimals
92
+
93
+ Returns:
94
+ Market cap in lamports
95
+ """
96
+ if base_reserve == 0:
97
+ return 0
98
+
99
+ # Price = quote_reserve / base_reserve
100
+ # Market cap = supply * price
101
+ return floor_div(supply * quote_reserve, base_reserve)
102
+
103
+
104
+ def is_pump_pool(mint: Pubkey, creator: Pubkey) -> bool:
105
+ """
106
+ Check if a pool is a pump pool (created via pump.fun)
107
+
108
+ Args:
109
+ mint: Token mint address
110
+ creator: Pool creator address
111
+
112
+ Returns:
113
+ True if it's a pump pool
114
+ """
115
+ # This would need to be implemented based on specific pump.fun detection logic
116
+ # For now, returning False as placeholder
117
+ return False
118
+
119
+
120
+ def calculate_swap_price(
121
+ amount_in: int,
122
+ reserve_in: int,
123
+ reserve_out: int,
124
+ fee_bps: int = 0
125
+ ) -> int:
126
+ """
127
+ Calculate output amount for a swap using constant product formula
128
+
129
+ Args:
130
+ amount_in: Input token amount
131
+ reserve_in: Input token reserve
132
+ reserve_out: Output token reserve
133
+ fee_bps: Total fee in basis points
134
+
135
+ Returns:
136
+ Output token amount
137
+ """
138
+ if reserve_in == 0 or reserve_out == 0:
139
+ raise ValueError("Invalid reserves")
140
+
141
+ # Apply fees to input amount
142
+ amount_in_with_fee = amount_in - fee(amount_in, fee_bps)
143
+
144
+ # Constant product formula: x * y = k
145
+ # amount_out = (reserve_out * amount_in_with_fee) / (reserve_in + amount_in_with_fee)
146
+ numerator = reserve_out * amount_in_with_fee
147
+ denominator = reserve_in + amount_in_with_fee
148
+
149
+ return floor_div(numerator, denominator)
150
+
151
+
152
+ def calculate_inverse_swap_price(
153
+ amount_out: int,
154
+ reserve_in: int,
155
+ reserve_out: int,
156
+ fee_bps: int = 0
157
+ ) -> int:
158
+ """
159
+ Calculate required input amount for a desired output amount
160
+
161
+ Args:
162
+ amount_out: Desired output token amount
163
+ reserve_in: Input token reserve
164
+ reserve_out: Output token reserve
165
+ fee_bps: Total fee in basis points
166
+
167
+ Returns:
168
+ Required input token amount
169
+ """
170
+ if reserve_in == 0 or reserve_out == 0:
171
+ raise ValueError("Invalid reserves")
172
+
173
+ if amount_out >= reserve_out:
174
+ raise ValueError("Insufficient liquidity")
175
+
176
+ # Calculate required input before fees
177
+ # amount_in_before_fee = (reserve_in * amount_out) / (reserve_out - amount_out)
178
+ numerator = reserve_in * amount_out
179
+ denominator = reserve_out - amount_out
180
+ amount_in_before_fee = ceil_div(numerator, denominator)
181
+
182
+ # Account for fees: amount_in = amount_in_before_fee / (1 - fee_rate)
183
+ if fee_bps > 0:
184
+ fee_rate = BASIS_POINTS - fee_bps
185
+ amount_in = ceil_div(amount_in_before_fee * BASIS_POINTS, fee_rate)
186
+ else:
187
+ amount_in = amount_in_before_fee
188
+
189
+ return amount_in
190
+
191
+
192
+ def calculate_lp_tokens_for_deposit(
193
+ token0_amount: int,
194
+ token1_amount: int,
195
+ reserve0: int,
196
+ reserve1: int,
197
+ total_lp_supply: int
198
+ ) -> int:
199
+ """
200
+ Calculate LP tokens to mint for a deposit
201
+
202
+ Args:
203
+ token0_amount: Amount of token0 being deposited
204
+ token1_amount: Amount of token1 being deposited
205
+ reserve0: Current reserve of token0
206
+ reserve1: Current reserve of token1
207
+ total_lp_supply: Current total LP token supply
208
+
209
+ Returns:
210
+ LP tokens to mint
211
+ """
212
+ if total_lp_supply == 0:
213
+ # Initial deposit - LP tokens = sqrt(token0 * token1)
214
+ return int(math.sqrt(token0_amount * token1_amount))
215
+
216
+ # Proportional deposit - LP tokens based on smaller ratio to prevent exploits
217
+ lp_from_token0 = floor_div(token0_amount * total_lp_supply, reserve0) if reserve0 > 0 else 0
218
+ lp_from_token1 = floor_div(token1_amount * total_lp_supply, reserve1) if reserve1 > 0 else 0
219
+
220
+ return min(lp_from_token0, lp_from_token1)
221
+
222
+
223
+ def calculate_tokens_for_lp_withdrawal(
224
+ lp_amount: int,
225
+ reserve0: int,
226
+ reserve1: int,
227
+ total_lp_supply: int
228
+ ) -> Tuple[int, int]:
229
+ """
230
+ Calculate token amounts for LP withdrawal
231
+
232
+ Args:
233
+ lp_amount: LP tokens to burn
234
+ reserve0: Current reserve of token0
235
+ reserve1: Current reserve of token1
236
+ total_lp_supply: Current total LP token supply
237
+
238
+ Returns:
239
+ Tuple of (token0_amount, token1_amount)
240
+ """
241
+ if total_lp_supply == 0:
242
+ return (0, 0)
243
+
244
+ token0_amount = floor_div(lp_amount * reserve0, total_lp_supply)
245
+ token1_amount = floor_div(lp_amount * reserve1, total_lp_supply)
246
+
247
+ return (token0_amount, token1_amount)
248
+
249
+
250
+ def validate_slippage(slippage_bps: int) -> None:
251
+ """
252
+ Validate slippage is within acceptable bounds
253
+
254
+ Args:
255
+ slippage_bps: Slippage in basis points
256
+
257
+ Raises:
258
+ ValueError: If slippage is invalid
259
+ """
260
+ if slippage_bps < 0:
261
+ raise ValueError("Slippage cannot be negative")
262
+ if slippage_bps > 10000: # 100%
263
+ raise ValueError("Slippage cannot exceed 100%")
264
+
265
+
266
+ def lamports_to_sol(lamports: int) -> float:
267
+ """Convert lamports to SOL"""
268
+ return lamports / LAMPORTS_PER_SOL
269
+
270
+
271
+ def sol_to_lamports(sol: float) -> int:
272
+ """Convert SOL to lamports"""
273
+ return int(sol * LAMPORTS_PER_SOL)
@@ -0,0 +1,153 @@
1
+ """
2
+ AMM-specific type definitions and data classes based on the Anchor program
3
+ """
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Optional, List, Dict
7
+ from solders.pubkey import Pubkey
8
+ from enum import Enum
9
+
10
+
11
+ class PoolStatus(Enum):
12
+ """Pool status enumeration"""
13
+ ACTIVE = 0
14
+ PAUSED = 1
15
+ DISABLED = 2
16
+
17
+
18
+ @dataclass
19
+ class Pool:
20
+ """Pool account structure"""
21
+ # Basic pool info
22
+ index: int
23
+ creator: Pubkey
24
+ base_mint: Pubkey
25
+ quote_mint: Pubkey
26
+ lp_mint: Pubkey
27
+
28
+ # Vaults
29
+ base_vault: Pubkey
30
+ quote_vault: Pubkey
31
+ base_vault_authority: Pubkey
32
+ quote_vault_authority: Pubkey
33
+
34
+ # Pool state
35
+ status: PoolStatus
36
+ created_at: int
37
+ updated_at: int
38
+
39
+ # Reserves and liquidity
40
+ total_lp_supply: int
41
+
42
+ # Fee collection
43
+ coin_creator: Optional[Pubkey] = None
44
+ coin_creator_fee_rate_bps: int = 0
45
+
46
+
47
+ @dataclass
48
+ class GlobalConfig:
49
+ """Global configuration for the AMM"""
50
+ # Admin settings
51
+ admin: Pubkey
52
+ fee_recipient: Pubkey
53
+
54
+ # Protocol settings
55
+ protocol_fee_rate_bps: int
56
+ creator_fee_rate_bps: int
57
+ max_pool_count: int
58
+
59
+ # Feature flags
60
+ is_paused: bool
61
+ is_mayhem_mode: bool
62
+
63
+ # Token incentives
64
+ token_incentives_enabled: bool
65
+ token_incentives_mint: Optional[Pubkey] = None
66
+ daily_token_incentives_amount: int = 0
67
+
68
+
69
+ @dataclass
70
+ class FeeConfig:
71
+ """Fee configuration with market cap tiers"""
72
+
73
+ @dataclass
74
+ class FeeTier:
75
+ """Individual fee tier"""
76
+ market_cap_threshold: int
77
+ lp_fee_rate_bps: int
78
+ protocol_fee_rate_bps: int
79
+ creator_fee_rate_bps: int
80
+
81
+ fee_tiers: List[FeeTier]
82
+ default_lp_fee_rate_bps: int
83
+ default_protocol_fee_rate_bps: int
84
+ default_creator_fee_rate_bps: int
85
+
86
+
87
+ @dataclass
88
+ class GlobalVolumeAccumulator:
89
+ """Global volume tracking"""
90
+ total_volume: int
91
+ total_fees: int
92
+ daily_volume: int
93
+ daily_fees: int
94
+ last_updated_day: int
95
+
96
+
97
+ @dataclass
98
+ class UserVolumeAccumulator:
99
+ """User-specific volume tracking"""
100
+ user: Pubkey
101
+ total_volume: int
102
+ total_fees: int
103
+ daily_volume: int
104
+ daily_fees: int
105
+ last_updated_day: int
106
+
107
+ # Token incentives tracking
108
+ unclaimed_token_incentives: int
109
+ last_claim_day: int
110
+
111
+
112
+ @dataclass
113
+ class ComputeFeesResult:
114
+ """Result of fee calculations"""
115
+ lp_fee_bps: int
116
+ protocol_fee_bps: int
117
+ creator_fee_bps: int
118
+ total_fee_bps: int
119
+
120
+
121
+ @dataclass
122
+ class SwapParams:
123
+ """Parameters for swap operations"""
124
+ amount_in: int
125
+ minimum_amount_out: int
126
+ slippage_bps: int
127
+
128
+
129
+ @dataclass
130
+ class LiquidityParams:
131
+ """Parameters for liquidity operations"""
132
+ max_base: int
133
+ max_quote: int
134
+ lp_token_amount: int
135
+ slippage_bps: int
136
+
137
+
138
+ @dataclass
139
+ class PoolReserves:
140
+ """Pool reserve amounts"""
141
+ base_reserve: int
142
+ quote_reserve: int
143
+ lp_supply: int
144
+
145
+
146
+ @dataclass
147
+ class MarketData:
148
+ """Market data for a pool"""
149
+ market_cap: int
150
+ price: float
151
+ volume_24h: int
152
+ fees_24h: int
153
+ tvl: int # Total Value Locked
@@ -0,0 +1,193 @@
1
+ """
2
+ SDK-specific type definitions and data classes
3
+ """
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Optional, List, Dict, Any
7
+ from solders.pubkey import Pubkey
8
+ from solders.account import Account
9
+ from solana.rpc.types import TokenAccountOpts
10
+
11
+
12
+ @dataclass
13
+ class DepositBaseResult:
14
+ quote: int
15
+ lp_token: int
16
+ max_base: int
17
+ max_quote: int
18
+
19
+
20
+ @dataclass
21
+ class DepositQuoteAndLpTokenFromBaseResult:
22
+ quote: int
23
+ lp_token: int
24
+
25
+
26
+ @dataclass
27
+ class DepositQuoteResult:
28
+ base: int
29
+ lp_token: int
30
+ max_base: int
31
+ max_quote: int
32
+
33
+
34
+ @dataclass
35
+ class DepositBaseAndLpTokenFromQuoteResult:
36
+ base: int
37
+ lp_token: int
38
+
39
+
40
+ @dataclass
41
+ class DepositLpTokenResult:
42
+ max_base: int
43
+ max_quote: int
44
+
45
+
46
+ @dataclass
47
+ class WithdrawResult:
48
+ base: int
49
+ quote: int
50
+ min_base: int
51
+ min_quote: int
52
+
53
+
54
+ @dataclass
55
+ class WithdrawAutocompleteResult:
56
+ base: int
57
+ quote: int
58
+
59
+
60
+ @dataclass
61
+ class BuyBaseInputResult:
62
+ internal_quote_amount: int
63
+ ui_quote: int
64
+ max_quote: int
65
+
66
+
67
+ @dataclass
68
+ class BuyQuoteInputResult:
69
+ base: int
70
+ internal_quote_without_fees: int
71
+ max_quote: int
72
+
73
+
74
+ @dataclass
75
+ class SellBaseInputResult:
76
+ ui_quote: int
77
+ min_quote: int
78
+ internal_quote_amount_out: int
79
+
80
+
81
+ @dataclass
82
+ class SellQuoteInputResult:
83
+ internal_raw_quote: int
84
+ base: int
85
+ min_quote: int
86
+
87
+
88
+ @dataclass
89
+ class SwapAccounts:
90
+ """Accounts needed for swap operations"""
91
+ user: Pubkey
92
+ pool: Pubkey
93
+ base_mint: Pubkey
94
+ quote_mint: Pubkey
95
+ lp_mint: Pubkey
96
+ base_vault: Pubkey
97
+ quote_vault: Pubkey
98
+ user_base_ata: Pubkey
99
+ user_quote_ata: Pubkey
100
+ base_vault_authority: Pubkey
101
+ quote_vault_authority: Pubkey
102
+ fee_recipient: Pubkey
103
+
104
+
105
+ @dataclass
106
+ class LiquidityAccounts:
107
+ """Accounts needed for liquidity operations"""
108
+ user: Pubkey
109
+ pool: Pubkey
110
+ base_mint: Pubkey
111
+ quote_mint: Pubkey
112
+ lp_mint: Pubkey
113
+ base_vault: Pubkey
114
+ quote_vault: Pubkey
115
+ user_base_ata: Pubkey
116
+ user_quote_ata: Pubkey
117
+ user_lp_ata: Pubkey
118
+ base_vault_authority: Pubkey
119
+ quote_vault_authority: Pubkey
120
+
121
+
122
+ @dataclass
123
+ class CommonSolanaState:
124
+ """Base state common to all operations"""
125
+ global_config: "GlobalConfig"
126
+ fee_config: "FeeConfig"
127
+ global_volume_accumulator: "GlobalVolumeAccumulator"
128
+ user_volume_accumulator: Optional["UserVolumeAccumulator"] = None
129
+
130
+
131
+ @dataclass
132
+ class SwapSolanaState(CommonSolanaState):
133
+ """State for swap operations"""
134
+ pool: "Pool" = None
135
+ pool_base_amount: int = 0
136
+ pool_quote_amount: int = 0
137
+ accounts: SwapAccounts = None
138
+
139
+
140
+ @dataclass
141
+ class LiquiditySolanaState(CommonSolanaState):
142
+ """State for liquidity operations"""
143
+ pool: "Pool" = None
144
+ pool_base_amount: int = 0
145
+ pool_quote_amount: int = 0
146
+ lp_total_supply: int = 0
147
+ accounts: LiquidityAccounts = None
148
+
149
+
150
+ @dataclass
151
+ class CreatePoolSolanaState(CommonSolanaState):
152
+ """State for pool creation"""
153
+ index: int = 0
154
+ creator: Pubkey = None
155
+ base_mint: Pubkey = None
156
+ quote_mint: Pubkey = None
157
+ pool: Pubkey = None
158
+ lp_mint: Pubkey = None
159
+ base_vault: Pubkey = None
160
+ quote_vault: Pubkey = None
161
+ base_vault_authority: Pubkey = None
162
+ quote_vault_authority: Pubkey = None
163
+
164
+
165
+ @dataclass
166
+ class CollectCoinCreatorFeeSolanaState:
167
+ """State for collecting coin creator fees"""
168
+ creator: Pubkey
169
+ coin_creator_vault_ata: Pubkey
170
+ coin_creator_vault_authority: Pubkey
171
+ creator_ata: Pubkey
172
+ mint: Pubkey
173
+
174
+
175
+ @dataclass
176
+ class TokenAccount:
177
+ """Represents a token account"""
178
+ address: Pubkey
179
+ mint: Pubkey
180
+ owner: Pubkey
181
+ amount: int
182
+ decimals: int
183
+
184
+
185
+ @dataclass
186
+ class MintInfo:
187
+ """Represents mint information"""
188
+ address: Pubkey
189
+ mint_authority: Optional[Pubkey]
190
+ supply: int
191
+ decimals: int
192
+ is_initialized: bool
193
+ freeze_authority: Optional[Pubkey]