@intentsolutionsio/flash-loan-simulator 1.0.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/.claude-plugin/plugin.json +22 -0
- package/LICENSE +21 -0
- package/README.md +411 -0
- package/agents/flashloan-agent.md +261 -0
- package/package.json +43 -0
- package/skills/simulating-flash-loans/ARD.md +454 -0
- package/skills/simulating-flash-loans/PRD.md +239 -0
- package/skills/simulating-flash-loans/SKILL.md +109 -0
- package/skills/simulating-flash-loans/config/settings.yaml +241 -0
- package/skills/simulating-flash-loans/references/errors.md +297 -0
- package/skills/simulating-flash-loans/references/examples.md +532 -0
- package/skills/simulating-flash-loans/references/implementation.md +73 -0
- package/skills/simulating-flash-loans/scripts/flash_simulator.py +492 -0
- package/skills/simulating-flash-loans/scripts/formatters.py +512 -0
- package/skills/simulating-flash-loans/scripts/profit_calculator.py +315 -0
- package/skills/simulating-flash-loans/scripts/protocol_adapters.py +416 -0
- package/skills/simulating-flash-loans/scripts/risk_assessor.py +439 -0
- package/skills/simulating-flash-loans/scripts/strategy_engine.py +596 -0
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Flash Loan Simulator - Main CLI Entry Point.
|
|
4
|
+
|
|
5
|
+
Simulates flash loan strategies across DeFi protocols with:
|
|
6
|
+
- Profitability analysis
|
|
7
|
+
- Gas cost estimation
|
|
8
|
+
- Risk assessment
|
|
9
|
+
- Provider comparison
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
python flash_simulator.py arbitrage ETH USDC 100 --dex-buy sushiswap --dex-sell uniswap
|
|
13
|
+
python flash_simulator.py liquidation --protocol aave --health-factor 0.95
|
|
14
|
+
python flash_simulator.py triangular ETH USDC WBTC ETH --amount 50
|
|
15
|
+
python flash_simulator.py compare ETH 100
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import sys
|
|
20
|
+
from decimal import Decimal, InvalidOperation
|
|
21
|
+
from typing import Optional
|
|
22
|
+
|
|
23
|
+
from strategy_engine import (
|
|
24
|
+
StrategyFactory,
|
|
25
|
+
StrategyType,
|
|
26
|
+
ArbitrageParams,
|
|
27
|
+
TriangularArbitrageParams,
|
|
28
|
+
LiquidationParams,
|
|
29
|
+
)
|
|
30
|
+
from profit_calculator import ProfitCalculator
|
|
31
|
+
from risk_assessor import RiskAssessor
|
|
32
|
+
from protocol_adapters import ProviderManager
|
|
33
|
+
from formatters import ConsoleFormatter, JSONFormatter, MarkdownFormatter
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def parse_args() -> argparse.Namespace:
|
|
37
|
+
"""Parse command line arguments."""
|
|
38
|
+
parser = argparse.ArgumentParser(
|
|
39
|
+
description="Flash Loan Strategy Simulator",
|
|
40
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
41
|
+
epilog="""
|
|
42
|
+
Examples:
|
|
43
|
+
# Simple arbitrage simulation
|
|
44
|
+
%(prog)s arbitrage ETH USDC 100 --dex-buy sushiswap --dex-sell uniswap
|
|
45
|
+
|
|
46
|
+
# Triangular arbitrage
|
|
47
|
+
%(prog)s triangular ETH USDC WBTC ETH --amount 50
|
|
48
|
+
|
|
49
|
+
# Liquidation profitability
|
|
50
|
+
%(prog)s liquidation --protocol aave --health-factor 0.95
|
|
51
|
+
|
|
52
|
+
# Compare providers
|
|
53
|
+
%(prog)s compare ETH 100
|
|
54
|
+
|
|
55
|
+
# Full analysis with risk assessment
|
|
56
|
+
%(prog)s arbitrage ETH USDC 100 --full --risk-analysis
|
|
57
|
+
|
|
58
|
+
# JSON output for integration
|
|
59
|
+
%(prog)s arbitrage ETH USDC 100 --output json > result.json
|
|
60
|
+
|
|
61
|
+
Providers:
|
|
62
|
+
aave - Aave V3 (0.09% fee, multi-chain)
|
|
63
|
+
dydx - dYdX (0% fee, Ethereum only)
|
|
64
|
+
balancer - Balancer (0.01% fee, multi-chain)
|
|
65
|
+
uniswap - Uniswap V3 (~0.3% implicit, flash swap)
|
|
66
|
+
|
|
67
|
+
DEXes:
|
|
68
|
+
uniswap, sushiswap, curve, balancer, 1inch
|
|
69
|
+
|
|
70
|
+
EDUCATIONAL DISCLAIMER:
|
|
71
|
+
This tool is for simulation and learning only.
|
|
72
|
+
Flash loans carry significant risks. Never deploy
|
|
73
|
+
untested code. Start with testnets.
|
|
74
|
+
""",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
subparsers = parser.add_subparsers(dest="command", help="Simulation type")
|
|
78
|
+
|
|
79
|
+
# Arbitrage subcommand
|
|
80
|
+
arb_parser = subparsers.add_parser(
|
|
81
|
+
"arbitrage", help="Simple two-DEX arbitrage simulation"
|
|
82
|
+
)
|
|
83
|
+
arb_parser.add_argument(
|
|
84
|
+
"input_token", help="Input token (e.g., ETH)"
|
|
85
|
+
)
|
|
86
|
+
arb_parser.add_argument(
|
|
87
|
+
"output_token", help="Output token (e.g., USDC)"
|
|
88
|
+
)
|
|
89
|
+
arb_parser.add_argument(
|
|
90
|
+
"amount", type=str, help="Loan amount"
|
|
91
|
+
)
|
|
92
|
+
arb_parser.add_argument(
|
|
93
|
+
"--dex-buy", default="sushiswap", help="DEX to buy on (default: sushiswap)"
|
|
94
|
+
)
|
|
95
|
+
arb_parser.add_argument(
|
|
96
|
+
"--dex-sell", default="uniswap", help="DEX to sell on (default: uniswap)"
|
|
97
|
+
)
|
|
98
|
+
arb_parser.add_argument(
|
|
99
|
+
"--provider", default="aave", help="Flash loan provider (default: aave)"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Triangular arbitrage subcommand
|
|
103
|
+
tri_parser = subparsers.add_parser(
|
|
104
|
+
"triangular", help="Multi-hop circular arbitrage simulation"
|
|
105
|
+
)
|
|
106
|
+
tri_parser.add_argument(
|
|
107
|
+
"tokens", nargs="+", help="Token path (e.g., ETH USDC WBTC ETH)"
|
|
108
|
+
)
|
|
109
|
+
tri_parser.add_argument(
|
|
110
|
+
"--amount", type=str, required=True, help="Loan amount"
|
|
111
|
+
)
|
|
112
|
+
tri_parser.add_argument(
|
|
113
|
+
"--provider", default="aave", help="Flash loan provider (default: aave)"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Liquidation subcommand
|
|
117
|
+
liq_parser = subparsers.add_parser(
|
|
118
|
+
"liquidation", help="Liquidation opportunity analysis"
|
|
119
|
+
)
|
|
120
|
+
liq_parser.add_argument(
|
|
121
|
+
"--protocol", default="aave", help="Lending protocol (default: aave)"
|
|
122
|
+
)
|
|
123
|
+
liq_parser.add_argument(
|
|
124
|
+
"--health-factor",
|
|
125
|
+
type=float,
|
|
126
|
+
default=0.95,
|
|
127
|
+
help="Health factor threshold (default: 0.95)",
|
|
128
|
+
)
|
|
129
|
+
liq_parser.add_argument(
|
|
130
|
+
"--collateral", default="ETH", help="Collateral asset (default: ETH)"
|
|
131
|
+
)
|
|
132
|
+
liq_parser.add_argument(
|
|
133
|
+
"--debt", default="USDC", help="Debt asset (default: USDC)"
|
|
134
|
+
)
|
|
135
|
+
liq_parser.add_argument(
|
|
136
|
+
"--amount", type=str, default="10", help="Debt amount to liquidate"
|
|
137
|
+
)
|
|
138
|
+
liq_parser.add_argument(
|
|
139
|
+
"--provider", default="aave", help="Flash loan provider (default: aave)"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Compare providers subcommand
|
|
143
|
+
cmp_parser = subparsers.add_parser(
|
|
144
|
+
"compare", help="Compare flash loan providers"
|
|
145
|
+
)
|
|
146
|
+
cmp_parser.add_argument("asset", help="Asset to borrow (e.g., ETH)")
|
|
147
|
+
cmp_parser.add_argument("amount", type=str, help="Amount to borrow")
|
|
148
|
+
cmp_parser.add_argument(
|
|
149
|
+
"--chain", default="ethereum", help="Chain (default: ethereum)"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Global options
|
|
153
|
+
for sub in [arb_parser, tri_parser, liq_parser]:
|
|
154
|
+
sub.add_argument(
|
|
155
|
+
"--compare-providers",
|
|
156
|
+
action="store_true",
|
|
157
|
+
help="Compare all providers for this strategy",
|
|
158
|
+
)
|
|
159
|
+
sub.add_argument(
|
|
160
|
+
"--risk-analysis",
|
|
161
|
+
action="store_true",
|
|
162
|
+
help="Include risk assessment",
|
|
163
|
+
)
|
|
164
|
+
sub.add_argument(
|
|
165
|
+
"--full",
|
|
166
|
+
action="store_true",
|
|
167
|
+
help="Full analysis (breakdown + risk + providers)",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Output options for all subcommands
|
|
171
|
+
for sub in [arb_parser, tri_parser, liq_parser, cmp_parser]:
|
|
172
|
+
sub.add_argument(
|
|
173
|
+
"--output",
|
|
174
|
+
choices=["console", "json", "markdown"],
|
|
175
|
+
default="console",
|
|
176
|
+
help="Output format (default: console)",
|
|
177
|
+
)
|
|
178
|
+
sub.add_argument(
|
|
179
|
+
"--eth-price",
|
|
180
|
+
type=float,
|
|
181
|
+
default=2500.0,
|
|
182
|
+
help="ETH price in USD (default: 2500)",
|
|
183
|
+
)
|
|
184
|
+
sub.add_argument(
|
|
185
|
+
"--gas-price",
|
|
186
|
+
type=float,
|
|
187
|
+
default=30.0,
|
|
188
|
+
help="Gas price in gwei (default: 30)",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
return parser.parse_args()
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def run_arbitrage(args: argparse.Namespace) -> int:
|
|
195
|
+
"""Run simple arbitrage simulation."""
|
|
196
|
+
try:
|
|
197
|
+
amount = Decimal(args.amount)
|
|
198
|
+
except InvalidOperation:
|
|
199
|
+
print(f"Error: Invalid amount '{args.amount}'", file=sys.stderr)
|
|
200
|
+
return 1
|
|
201
|
+
|
|
202
|
+
# Create strategy
|
|
203
|
+
factory = StrategyFactory()
|
|
204
|
+
strategy = factory.create(StrategyType.SIMPLE_ARBITRAGE)
|
|
205
|
+
|
|
206
|
+
params = ArbitrageParams(
|
|
207
|
+
input_token=args.input_token.upper(),
|
|
208
|
+
output_token=args.output_token.upper(),
|
|
209
|
+
amount=amount,
|
|
210
|
+
dex_buy=args.dex_buy.lower(),
|
|
211
|
+
dex_sell=args.dex_sell.lower(),
|
|
212
|
+
provider=args.provider.lower(),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Run simulation
|
|
216
|
+
result = strategy.simulate(params)
|
|
217
|
+
|
|
218
|
+
# Calculate extras if needed
|
|
219
|
+
calculator = None
|
|
220
|
+
breakdown = None
|
|
221
|
+
assessor = None
|
|
222
|
+
assessment = None
|
|
223
|
+
providers = None
|
|
224
|
+
|
|
225
|
+
if args.full or hasattr(args, "compare_providers") and args.compare_providers:
|
|
226
|
+
calculator = ProfitCalculator(
|
|
227
|
+
eth_price_usd=args.eth_price, gas_price_gwei=args.gas_price
|
|
228
|
+
)
|
|
229
|
+
breakdown = calculator.calculate_breakdown(result)
|
|
230
|
+
|
|
231
|
+
if args.full or (hasattr(args, "risk_analysis") and args.risk_analysis):
|
|
232
|
+
assessor = RiskAssessor(eth_price_usd=args.eth_price)
|
|
233
|
+
assessment = assessor.assess(result)
|
|
234
|
+
|
|
235
|
+
if args.full or (hasattr(args, "compare_providers") and args.compare_providers):
|
|
236
|
+
manager = ProviderManager()
|
|
237
|
+
providers = manager.compare_providers(
|
|
238
|
+
args.input_token.upper(), amount, "ethereum"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# Format output
|
|
242
|
+
output_result(args, result, breakdown, assessment, providers)
|
|
243
|
+
|
|
244
|
+
return 0 if result.is_profitable else 1
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def run_triangular(args: argparse.Namespace) -> int:
|
|
248
|
+
"""Run triangular arbitrage simulation."""
|
|
249
|
+
if len(args.tokens) < 3:
|
|
250
|
+
print("Error: Triangular arbitrage requires at least 3 tokens", file=sys.stderr)
|
|
251
|
+
return 1
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
amount = Decimal(args.amount)
|
|
255
|
+
except InvalidOperation:
|
|
256
|
+
print(f"Error: Invalid amount '{args.amount}'", file=sys.stderr)
|
|
257
|
+
return 1
|
|
258
|
+
|
|
259
|
+
# Create strategy
|
|
260
|
+
factory = StrategyFactory()
|
|
261
|
+
strategy = factory.create(StrategyType.TRIANGULAR_ARBITRAGE)
|
|
262
|
+
|
|
263
|
+
params = TriangularArbitrageParams(
|
|
264
|
+
tokens=[t.upper() for t in args.tokens],
|
|
265
|
+
amount=amount,
|
|
266
|
+
provider=args.provider.lower(),
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Run simulation
|
|
270
|
+
result = strategy.simulate(params)
|
|
271
|
+
|
|
272
|
+
# Calculate extras
|
|
273
|
+
calculator = None
|
|
274
|
+
breakdown = None
|
|
275
|
+
assessment = None
|
|
276
|
+
providers = None
|
|
277
|
+
|
|
278
|
+
if args.full:
|
|
279
|
+
calculator = ProfitCalculator(
|
|
280
|
+
eth_price_usd=args.eth_price, gas_price_gwei=args.gas_price
|
|
281
|
+
)
|
|
282
|
+
breakdown = calculator.calculate_breakdown(result)
|
|
283
|
+
|
|
284
|
+
assessor = RiskAssessor(eth_price_usd=args.eth_price)
|
|
285
|
+
assessment = assessor.assess(result)
|
|
286
|
+
|
|
287
|
+
manager = ProviderManager()
|
|
288
|
+
providers = manager.compare_providers(
|
|
289
|
+
args.tokens[0].upper(), amount, "ethereum"
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
if hasattr(args, "risk_analysis") and args.risk_analysis:
|
|
293
|
+
assessor = RiskAssessor(eth_price_usd=args.eth_price)
|
|
294
|
+
assessment = assessor.assess(result)
|
|
295
|
+
|
|
296
|
+
# Format output
|
|
297
|
+
output_result(args, result, breakdown, assessment, providers)
|
|
298
|
+
|
|
299
|
+
return 0 if result.is_profitable else 1
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def run_liquidation(args: argparse.Namespace) -> int:
|
|
303
|
+
"""Run liquidation simulation."""
|
|
304
|
+
try:
|
|
305
|
+
amount = Decimal(args.amount)
|
|
306
|
+
except InvalidOperation:
|
|
307
|
+
print(f"Error: Invalid amount '{args.amount}'", file=sys.stderr)
|
|
308
|
+
return 1
|
|
309
|
+
|
|
310
|
+
# Create strategy
|
|
311
|
+
factory = StrategyFactory()
|
|
312
|
+
strategy = factory.create(StrategyType.LIQUIDATION)
|
|
313
|
+
|
|
314
|
+
params = LiquidationParams(
|
|
315
|
+
collateral_asset=args.collateral.upper(),
|
|
316
|
+
debt_asset=args.debt.upper(),
|
|
317
|
+
debt_amount=amount,
|
|
318
|
+
health_factor=args.health_factor,
|
|
319
|
+
lending_protocol=args.protocol.lower(),
|
|
320
|
+
provider=args.provider.lower(),
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
# Run simulation
|
|
324
|
+
result = strategy.simulate(params)
|
|
325
|
+
|
|
326
|
+
# Calculate extras
|
|
327
|
+
calculator = None
|
|
328
|
+
breakdown = None
|
|
329
|
+
assessment = None
|
|
330
|
+
providers = None
|
|
331
|
+
|
|
332
|
+
if args.full:
|
|
333
|
+
calculator = ProfitCalculator(
|
|
334
|
+
eth_price_usd=args.eth_price, gas_price_gwei=args.gas_price
|
|
335
|
+
)
|
|
336
|
+
breakdown = calculator.calculate_breakdown(result)
|
|
337
|
+
|
|
338
|
+
assessor = RiskAssessor(eth_price_usd=args.eth_price)
|
|
339
|
+
assessment = assessor.assess(result)
|
|
340
|
+
|
|
341
|
+
manager = ProviderManager()
|
|
342
|
+
providers = manager.compare_providers(
|
|
343
|
+
args.debt.upper(), amount, "ethereum"
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
if hasattr(args, "risk_analysis") and args.risk_analysis:
|
|
347
|
+
assessor = RiskAssessor(eth_price_usd=args.eth_price)
|
|
348
|
+
assessment = assessor.assess(result)
|
|
349
|
+
|
|
350
|
+
# Format output
|
|
351
|
+
output_result(args, result, breakdown, assessment, providers)
|
|
352
|
+
|
|
353
|
+
return 0 if result.is_profitable else 1
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def run_compare(args: argparse.Namespace) -> int:
|
|
357
|
+
"""Run provider comparison."""
|
|
358
|
+
try:
|
|
359
|
+
amount = Decimal(args.amount)
|
|
360
|
+
except InvalidOperation:
|
|
361
|
+
print(f"Error: Invalid amount '{args.amount}'", file=sys.stderr)
|
|
362
|
+
return 1
|
|
363
|
+
|
|
364
|
+
manager = ProviderManager()
|
|
365
|
+
providers = manager.compare_providers(
|
|
366
|
+
args.asset.upper(), amount, args.chain.lower()
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
if not providers:
|
|
370
|
+
print(
|
|
371
|
+
f"No providers support {amount} {args.asset} on {args.chain}",
|
|
372
|
+
file=sys.stderr,
|
|
373
|
+
)
|
|
374
|
+
return 1
|
|
375
|
+
|
|
376
|
+
# Format output
|
|
377
|
+
if args.output == "json":
|
|
378
|
+
json_fmt = JSONFormatter()
|
|
379
|
+
# Create a minimal result for JSON output
|
|
380
|
+
output = {
|
|
381
|
+
"comparison": {
|
|
382
|
+
"asset": args.asset.upper(),
|
|
383
|
+
"amount": float(amount),
|
|
384
|
+
"chain": args.chain,
|
|
385
|
+
},
|
|
386
|
+
"providers": [
|
|
387
|
+
{
|
|
388
|
+
"name": p.name,
|
|
389
|
+
"fee_rate": float(p.fee_rate),
|
|
390
|
+
"fee_amount": float(p.fee_amount),
|
|
391
|
+
"max_available": float(p.max_available),
|
|
392
|
+
"gas_overhead": p.gas_overhead,
|
|
393
|
+
"supported_chains": p.supported_chains,
|
|
394
|
+
}
|
|
395
|
+
for p in providers
|
|
396
|
+
],
|
|
397
|
+
}
|
|
398
|
+
import json
|
|
399
|
+
print(json.dumps(output, indent=2))
|
|
400
|
+
else:
|
|
401
|
+
console = ConsoleFormatter()
|
|
402
|
+
print(console.format_provider_comparison(providers, args.asset.upper(), amount))
|
|
403
|
+
|
|
404
|
+
return 0
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def output_result(
|
|
408
|
+
args: argparse.Namespace,
|
|
409
|
+
result,
|
|
410
|
+
breakdown=None,
|
|
411
|
+
assessment=None,
|
|
412
|
+
providers=None,
|
|
413
|
+
) -> None:
|
|
414
|
+
"""Output simulation result in requested format."""
|
|
415
|
+
if args.output == "json":
|
|
416
|
+
json_fmt = JSONFormatter()
|
|
417
|
+
print(json_fmt.format_full_report(result, breakdown, assessment, providers))
|
|
418
|
+
|
|
419
|
+
elif args.output == "markdown":
|
|
420
|
+
md_fmt = MarkdownFormatter()
|
|
421
|
+
print(md_fmt.format_simulation_report(result, breakdown, assessment))
|
|
422
|
+
|
|
423
|
+
else: # console (default)
|
|
424
|
+
console = ConsoleFormatter()
|
|
425
|
+
|
|
426
|
+
# Always show strategy result
|
|
427
|
+
print(console.format_strategy_result(result))
|
|
428
|
+
|
|
429
|
+
# Show breakdown if calculated
|
|
430
|
+
if breakdown:
|
|
431
|
+
print(console.format_profit_breakdown(breakdown))
|
|
432
|
+
|
|
433
|
+
# Show risk assessment if calculated
|
|
434
|
+
if assessment:
|
|
435
|
+
print(console.format_risk_assessment(assessment))
|
|
436
|
+
|
|
437
|
+
# Show provider comparison if calculated
|
|
438
|
+
if providers:
|
|
439
|
+
print(
|
|
440
|
+
console.format_provider_comparison(
|
|
441
|
+
providers, result.loan_asset, result.loan_amount
|
|
442
|
+
)
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
# Always show quick summary at end
|
|
446
|
+
print(console.format_quick_summary(result, assessment))
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def print_banner():
|
|
450
|
+
"""Print startup banner."""
|
|
451
|
+
banner = """
|
|
452
|
+
╔══════════════════════════════════════════════════════════════════╗
|
|
453
|
+
║ FLASH LOAN SIMULATOR v1.0.0 ║
|
|
454
|
+
║ ║
|
|
455
|
+
║ Simulate flash loan strategies across DeFi protocols ║
|
|
456
|
+
║ Providers: Aave V3 | dYdX | Balancer | Uniswap V3 ║
|
|
457
|
+
║ ║
|
|
458
|
+
║ ⚠️ EDUCATIONAL PURPOSES ONLY - Not financial advice ║
|
|
459
|
+
╚══════════════════════════════════════════════════════════════════╝
|
|
460
|
+
"""
|
|
461
|
+
print(banner, file=sys.stderr)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def main() -> int:
|
|
465
|
+
"""Main entry point."""
|
|
466
|
+
args = parse_args()
|
|
467
|
+
|
|
468
|
+
if not args.command:
|
|
469
|
+
print_banner()
|
|
470
|
+
print("Use --help for usage information", file=sys.stderr)
|
|
471
|
+
print("\nQuick start:")
|
|
472
|
+
print(" flash_simulator.py arbitrage ETH USDC 100")
|
|
473
|
+
print(" flash_simulator.py compare ETH 100")
|
|
474
|
+
print(" flash_simulator.py liquidation --protocol aave")
|
|
475
|
+
return 1
|
|
476
|
+
|
|
477
|
+
# Run appropriate command
|
|
478
|
+
if args.command == "arbitrage":
|
|
479
|
+
return run_arbitrage(args)
|
|
480
|
+
elif args.command == "triangular":
|
|
481
|
+
return run_triangular(args)
|
|
482
|
+
elif args.command == "liquidation":
|
|
483
|
+
return run_liquidation(args)
|
|
484
|
+
elif args.command == "compare":
|
|
485
|
+
return run_compare(args)
|
|
486
|
+
else:
|
|
487
|
+
print(f"Unknown command: {args.command}", file=sys.stderr)
|
|
488
|
+
return 1
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
if __name__ == "__main__":
|
|
492
|
+
sys.exit(main())
|