wayfinder-paths 0.1.19__py3-none-any.whl → 0.1.20__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.

Potentially problematic release.


This version of wayfinder-paths might be problematic. Click here for more details.

Files changed (98) hide show
  1. wayfinder_paths/__init__.py +0 -2
  2. wayfinder_paths/adapters/balance_adapter/README.md +59 -45
  3. wayfinder_paths/adapters/balance_adapter/adapter.py +0 -21
  4. wayfinder_paths/adapters/balance_adapter/test_adapter.py +0 -14
  5. wayfinder_paths/adapters/brap_adapter/README.md +61 -184
  6. wayfinder_paths/adapters/brap_adapter/__init__.py +0 -4
  7. wayfinder_paths/adapters/brap_adapter/adapter.py +0 -147
  8. wayfinder_paths/adapters/brap_adapter/test_adapter.py +0 -15
  9. wayfinder_paths/adapters/hyperlend_adapter/__init__.py +0 -4
  10. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +0 -9
  11. wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +0 -17
  12. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +3 -312
  13. wayfinder_paths/adapters/hyperliquid_adapter/executor.py +1 -71
  14. wayfinder_paths/adapters/hyperliquid_adapter/paired_filler.py +0 -57
  15. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter.py +0 -17
  16. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter_live.py +2 -42
  17. wayfinder_paths/adapters/hyperliquid_adapter/test_executor.py +1 -9
  18. wayfinder_paths/adapters/hyperliquid_adapter/test_utils.py +15 -47
  19. wayfinder_paths/adapters/hyperliquid_adapter/utils.py +0 -7
  20. wayfinder_paths/adapters/ledger_adapter/README.md +54 -74
  21. wayfinder_paths/adapters/ledger_adapter/__init__.py +0 -4
  22. wayfinder_paths/adapters/ledger_adapter/adapter.py +0 -106
  23. wayfinder_paths/adapters/ledger_adapter/test_adapter.py +0 -12
  24. wayfinder_paths/adapters/moonwell_adapter/README.md +67 -106
  25. wayfinder_paths/adapters/moonwell_adapter/__init__.py +0 -4
  26. wayfinder_paths/adapters/moonwell_adapter/adapter.py +9 -121
  27. wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +84 -83
  28. wayfinder_paths/adapters/pool_adapter/README.md +30 -51
  29. wayfinder_paths/adapters/pool_adapter/__init__.py +0 -4
  30. wayfinder_paths/adapters/pool_adapter/adapter.py +0 -19
  31. wayfinder_paths/adapters/pool_adapter/test_adapter.py +0 -8
  32. wayfinder_paths/adapters/token_adapter/README.md +41 -49
  33. wayfinder_paths/adapters/token_adapter/adapter.py +0 -32
  34. wayfinder_paths/adapters/token_adapter/test_adapter.py +1 -12
  35. wayfinder_paths/conftest.py +0 -8
  36. wayfinder_paths/core/__init__.py +0 -2
  37. wayfinder_paths/core/adapters/BaseAdapter.py +0 -22
  38. wayfinder_paths/core/adapters/__init__.py +0 -5
  39. wayfinder_paths/core/adapters/models.py +0 -5
  40. wayfinder_paths/core/analytics/__init__.py +0 -2
  41. wayfinder_paths/core/analytics/bootstrap.py +0 -16
  42. wayfinder_paths/core/analytics/stats.py +0 -7
  43. wayfinder_paths/core/analytics/test_analytics.py +5 -34
  44. wayfinder_paths/core/clients/BRAPClient.py +0 -35
  45. wayfinder_paths/core/clients/ClientManager.py +0 -51
  46. wayfinder_paths/core/clients/HyperlendClient.py +0 -77
  47. wayfinder_paths/core/clients/LedgerClient.py +2 -122
  48. wayfinder_paths/core/clients/PoolClient.py +0 -2
  49. wayfinder_paths/core/clients/TokenClient.py +0 -39
  50. wayfinder_paths/core/clients/WalletClient.py +0 -15
  51. wayfinder_paths/core/clients/WayfinderClient.py +0 -24
  52. wayfinder_paths/core/clients/__init__.py +0 -4
  53. wayfinder_paths/core/clients/protocols.py +25 -98
  54. wayfinder_paths/core/config.py +0 -24
  55. wayfinder_paths/core/constants/__init__.py +0 -7
  56. wayfinder_paths/core/constants/base.py +2 -9
  57. wayfinder_paths/core/constants/erc20_abi.py +0 -5
  58. wayfinder_paths/core/constants/hyperlend_abi.py +0 -7
  59. wayfinder_paths/core/constants/moonwell_abi.py +0 -35
  60. wayfinder_paths/core/engine/StrategyJob.py +0 -32
  61. wayfinder_paths/core/strategies/Strategy.py +0 -99
  62. wayfinder_paths/core/strategies/__init__.py +0 -2
  63. wayfinder_paths/core/utils/__init__.py +0 -1
  64. wayfinder_paths/core/utils/erc20_service.py +0 -1
  65. wayfinder_paths/core/utils/evm_helpers.py +0 -50
  66. wayfinder_paths/core/utils/transaction.py +0 -1
  67. wayfinder_paths/run_strategy.py +0 -46
  68. wayfinder_paths/scripts/create_strategy.py +0 -17
  69. wayfinder_paths/scripts/make_wallets.py +1 -4
  70. wayfinder_paths/strategies/basis_trading_strategy/README.md +71 -163
  71. wayfinder_paths/strategies/basis_trading_strategy/snapshot_mixin.py +0 -24
  72. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +36 -400
  73. wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +15 -64
  74. wayfinder_paths/strategies/basis_trading_strategy/types.py +0 -4
  75. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +65 -56
  76. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +4 -27
  77. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +0 -10
  78. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/README.md +71 -72
  79. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +23 -227
  80. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +120 -113
  81. wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +64 -59
  82. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +4 -44
  83. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +2 -35
  84. wayfinder_paths/templates/adapter/README.md +107 -46
  85. wayfinder_paths/templates/adapter/adapter.py +0 -9
  86. wayfinder_paths/templates/adapter/test_adapter.py +0 -19
  87. wayfinder_paths/templates/strategy/README.md +113 -59
  88. wayfinder_paths/templates/strategy/strategy.py +0 -22
  89. wayfinder_paths/templates/strategy/test_strategy.py +0 -28
  90. wayfinder_paths/tests/test_test_coverage.py +2 -12
  91. wayfinder_paths/tests/test_utils.py +1 -31
  92. wayfinder_paths-0.1.20.dist-info/METADATA +355 -0
  93. wayfinder_paths-0.1.20.dist-info/RECORD +129 -0
  94. wayfinder_paths/core/adapters/base.py +0 -5
  95. wayfinder_paths-0.1.19.dist-info/METADATA +0 -592
  96. wayfinder_paths-0.1.19.dist-info/RECORD +0 -130
  97. {wayfinder_paths-0.1.19.dist-info → wayfinder_paths-0.1.20.dist-info}/LICENSE +0 -0
  98. {wayfinder_paths-0.1.19.dist-info → wayfinder_paths-0.1.20.dist-info}/WHEEL +0 -0
@@ -1,5 +1,3 @@
1
- """Wayfinder Path - Trading strategies and adapters for automated strategy management"""
2
-
3
1
  __version__ = "0.1.0"
4
2
 
5
3
  # Re-export commonly used items for convenience
@@ -1,91 +1,105 @@
1
1
  # Balance Adapter
2
2
 
3
- Adapter that exposes wallet, token, and pool balances backed by `WalletClient`/`TokenClient` and now orchestrates transfers between the configured main/strategy wallets (with ledger bookkeeping).
3
+ Adapter for wallet and token balances with cross-wallet transfer capabilities.
4
4
 
5
- - Entrypoint: `adapters.balance_adapter.adapter.BalanceAdapter`
6
- - Tests: `test_adapter.py`
5
+ - **Type**: `BALANCE`
6
+ - **Module**: `wayfinder_paths.adapters.balance_adapter.adapter.BalanceAdapter`
7
7
 
8
- ## Capabilities
8
+ ## Overview
9
9
 
10
- The adapter provides both wallet read and wallet transfer capabilities. Ledger recording + wallet selection now live inside the adapter.
10
+ The BalanceAdapter provides:
11
+ - Token balance queries for any wallet
12
+ - Cross-wallet transfers between main and strategy wallets
13
+ - Automatic ledger recording for deposits/withdrawals
11
14
 
12
- ## Construction
15
+ ## Usage
13
16
 
14
17
  ```python
15
18
  from wayfinder_paths.adapters.balance_adapter.adapter import BalanceAdapter
16
19
 
20
+ adapter = BalanceAdapter(
21
+ config=config,
22
+ main_wallet_signing_callback=main_signing_cb,
23
+ strategy_wallet_signing_callback=strategy_signing_cb,
24
+ )
17
25
  ```
18
26
 
19
- ## API surface
27
+ ## Methods
20
28
 
21
- ### `get_balance(token_id: str, wallet_address: str)`
29
+ ### get_balance
22
30
 
23
- Returns the raw balance (as an integer) for a specific token on a wallet.
31
+ Get token balance for a wallet.
24
32
 
25
33
  ```python
26
- success, balance = await balance.get_balance(
34
+ success, balance = await adapter.get_balance(
27
35
  token_id="usd-coin-base",
28
- wallet_address=config["main_wallet"]["address"],
36
+ wallet_address="0x...",
37
+ chain_id=8453, # optional, auto-resolved from token
29
38
  )
30
39
  ```
31
40
 
32
- ### `get_pool_balance(pool_address: str, chain_id: int, user_address: str)`
41
+ **Returns**: `(bool, int)` - success flag and raw balance (in token units)
42
+
43
+ ### move_from_main_wallet_to_strategy_wallet
33
44
 
34
- Fetches the amount supplied to a specific pool, using the `/wallets/pool-balance` endpoint.
45
+ Transfer tokens from main wallet to strategy wallet with ledger recording.
35
46
 
36
47
  ```python
37
- success, amount = await balance.get_pool_balance(
38
- pool_address="0xPool",
39
- chain_id=8453,
40
- user_address=config["strategy_wallet"]["address"],
48
+ success, tx_hash = await adapter.move_from_main_wallet_to_strategy_wallet(
49
+ token_id="usd-coin-base",
50
+ amount=100.0, # human-readable amount
51
+ strategy_name="my_strategy",
52
+ skip_ledger=False,
41
53
  )
42
54
  ```
43
55
 
44
- ### `move_from_main_wallet_to_strategy_wallet(token_id: str, amount: float, strategy_name="unknown", skip_ledger=False)`
56
+ ### move_from_strategy_wallet_to_main_wallet
45
57
 
46
- Sends the specified token from the configured `main_wallet` to the strategy wallet, records the ledger deposit (unless `skip_ledger=True`), and returns the `(success, tx_result)` tuple from the underlying send helper.
58
+ Transfer tokens from strategy wallet back to main wallet.
47
59
 
48
60
  ```python
49
- success, tx = await balance.move_from_main_wallet_to_strategy_wallet(
61
+ success, tx_hash = await adapter.move_from_strategy_wallet_to_main_wallet(
50
62
  token_id="usd-coin-base",
51
- amount=1.5,
52
- strategy_name="MyStrategy",
63
+ amount=50.0,
64
+ strategy_name="my_strategy",
65
+ skip_ledger=False,
53
66
  )
54
67
  ```
55
68
 
56
- ### `move_from_strategy_wallet_to_main_wallet(token_id: str, amount: float, strategy_name="unknown", skip_ledger=False)`
69
+ ### send_to_address
57
70
 
58
- Mirrors the previous method but withdraws from the strategy wallet back to the main wallet while recording a ledger withdrawal entry.
71
+ Send tokens to an arbitrary address (e.g., bridge contract).
59
72
 
60
73
  ```python
61
- await balance.move_from_strategy_wallet_to_main_wallet(
74
+ success, tx_hash = await adapter.send_to_address(
62
75
  token_id="usd-coin-base",
63
- amount=0.75,
64
- strategy_name="MyStrategy",
76
+ amount=1000000, # raw amount
77
+ from_wallet=config["strategy_wallet"],
78
+ to_address="0xBridgeContract...",
79
+ signing_callback=strategy_signing_cb,
65
80
  )
66
81
  ```
67
82
 
68
- All methods return `(success: bool, payload: Any)` tuples. On failure the payload is an error string.
83
+ ## Configuration
69
84
 
70
- ## Usage inside strategies
85
+ The adapter requires wallet configuration in `config`:
71
86
 
72
87
  ```python
73
- class MyStrategy(Strategy):
74
- def __init__(self, config):
75
- super().__init__()
76
- balance_adapter = BalanceAdapter(config)
77
- self.register_adapters([balance_adapter])
78
- self.balance_adapter = balance_adapter
79
-
80
- async def _status(self):
81
- success, pool_balance = await self.balance_adapter.get_pool_balance(
82
- pool_address=self.current_pool["address"],
83
- chain_id=self.current_pool["chain"]["id"],
84
- user_address=self.config["strategy_wallet"]["address"],
85
- )
86
- return {"portfolio_value": float(pool_balance or 0), ...}
88
+ config = {
89
+ "main_wallet": {"address": "0x..."},
90
+ "strategy_wallet": {"address": "0x..."},
91
+ }
87
92
  ```
88
93
 
89
- ## Error handling and health checks
94
+ ## Dependencies
90
95
 
91
- Any exception raised by the underlying `WalletClient`/`TokenClient` is caught and emitted as a `(False, "message")` tuple. The inherited `health_check()` method reports adapter status plus dependency status, making it safe to call from `Strategy.health_check`.
96
+ - `WalletClient` - For balance queries
97
+ - `TokenClient` - For token metadata
98
+ - `LedgerAdapter` - For transaction recording
99
+ - `TokenAdapter` - For price lookups
100
+
101
+ ## Testing
102
+
103
+ ```bash
104
+ poetry run pytest wayfinder_paths/adapters/balance_adapter/ -v
105
+ ```
@@ -16,12 +16,10 @@ class BalanceAdapter(BaseAdapter):
16
16
  def __init__(
17
17
  self,
18
18
  config: dict[str, Any],
19
- simulation: bool = False,
20
19
  main_wallet_signing_callback=None,
21
20
  strategy_wallet_signing_callback=None,
22
21
  ):
23
22
  super().__init__("balance", config)
24
- self.simulation = simulation
25
23
  self.main_wallet_signing_callback = main_wallet_signing_callback
26
24
  self.strategy_wallet_signing_callback = strategy_wallet_signing_callback
27
25
  self.wallet_client = WalletClient()
@@ -30,7 +28,6 @@ class BalanceAdapter(BaseAdapter):
30
28
  self.ledger_adapter = LedgerAdapter()
31
29
 
32
30
  def _parse_balance(self, raw: Any) -> int:
33
- """Parse balance value to integer, handling various formats."""
34
31
  if raw is None:
35
32
  return 0
36
33
  try:
@@ -49,12 +46,6 @@ class BalanceAdapter(BaseAdapter):
49
46
  wallet_address: str,
50
47
  chain_id: int | None = None,
51
48
  ) -> tuple[bool, str | int]:
52
- """Get token or pool balance for a wallet.
53
-
54
- query: token_id/address string or a dict with a "token_id" key.
55
- token_id: alternative to query for convenience.
56
- """
57
- # Support both query= and token_id= for caller convenience
58
49
  effective_query = query if query is not None else token_id
59
50
  resolved = (
60
51
  effective_query
@@ -78,7 +69,6 @@ class BalanceAdapter(BaseAdapter):
78
69
  query=resolved,
79
70
  chain_id=int(chain_id),
80
71
  )
81
- # Use _parse_balance for consistent parsing (handles balance_raw or balance)
82
72
  raw = (
83
73
  data.get("balance_raw") or data.get("balance")
84
74
  if isinstance(data, dict)
@@ -95,7 +85,6 @@ class BalanceAdapter(BaseAdapter):
95
85
  strategy_name: str = "unknown",
96
86
  skip_ledger: bool = False,
97
87
  ) -> tuple[bool, Any]:
98
- """Move funds from the configured main wallet into the strategy wallet."""
99
88
  return await self._move_between_wallets(
100
89
  token_id=token_id,
101
90
  amount=amount,
@@ -114,7 +103,6 @@ class BalanceAdapter(BaseAdapter):
114
103
  strategy_name: str = "unknown",
115
104
  skip_ledger: bool = False,
116
105
  ) -> tuple[bool, Any]:
117
- """Move funds from the strategy wallet back into the main wallet."""
118
106
  return await self._move_between_wallets(
119
107
  token_id=token_id,
120
108
  amount=amount,
@@ -135,7 +123,6 @@ class BalanceAdapter(BaseAdapter):
135
123
  signing_callback=None,
136
124
  skip_ledger: bool = True,
137
125
  ) -> tuple[bool, Any]:
138
- """Send tokens from a wallet to an arbitrary address (e.g., bridge contract)."""
139
126
  from_address = self._wallet_address(from_wallet)
140
127
  if not from_address:
141
128
  return False, "from_wallet missing or invalid"
@@ -161,9 +148,6 @@ class BalanceAdapter(BaseAdapter):
161
148
  amount=int(amount),
162
149
  )
163
150
 
164
- if self.simulation:
165
- return True, {"simulation": tx}
166
-
167
151
  if not signing_callback:
168
152
  return False, "signing_callback is required"
169
153
 
@@ -220,11 +204,6 @@ class BalanceAdapter(BaseAdapter):
220
204
  return broadcast_result
221
205
 
222
206
  async def _send_tx(self, tx: dict[str, Any], from_address: str) -> tuple[bool, Any]:
223
- """Send transaction with simulation check, using appropriate signing callback."""
224
- if self.simulation:
225
- return True, {"simulation": tx}
226
-
227
- # Choose callback based on which wallet is sending
228
207
  main_wallet = self.config.get("main_wallet") or {}
229
208
  main_addr = main_wallet.get("address", "").lower()
230
209
 
@@ -6,23 +6,18 @@ from wayfinder_paths.adapters.balance_adapter.adapter import BalanceAdapter
6
6
 
7
7
 
8
8
  class TestBalanceAdapter:
9
- """Test cases for BalanceAdapter"""
10
-
11
9
  @pytest.fixture
12
10
  def mock_wallet_client(self):
13
- """Mock WalletClient for testing"""
14
11
  mock_client = AsyncMock()
15
12
  return mock_client
16
13
 
17
14
  @pytest.fixture
18
15
  def mock_token_client(self):
19
- """Mock TokenClient for testing"""
20
16
  mock_client = AsyncMock()
21
17
  return mock_client
22
18
 
23
19
  @pytest.fixture
24
20
  def adapter(self, mock_wallet_client, mock_token_client):
25
- """Create a BalanceAdapter instance with mocked clients for testing"""
26
21
  with (
27
22
  patch(
28
23
  "wayfinder_paths.adapters.balance_adapter.adapter.WalletClient",
@@ -37,26 +32,22 @@ class TestBalanceAdapter:
37
32
 
38
33
  @pytest.mark.asyncio
39
34
  async def test_health_check(self, adapter):
40
- """Test adapter health check"""
41
35
  health = await adapter.health_check()
42
36
  assert isinstance(health, dict)
43
37
  assert health.get("status") in {"healthy", "unhealthy", "error"}
44
38
 
45
39
  @pytest.mark.asyncio
46
40
  async def test_connect(self, adapter):
47
- """Test adapter connection"""
48
41
  ok = await adapter.connect()
49
42
  assert isinstance(ok, bool)
50
43
 
51
44
  def test_adapter_type(self, adapter):
52
- """Test adapter has adapter_type"""
53
45
  assert adapter.adapter_type == "BALANCE"
54
46
 
55
47
  @pytest.mark.asyncio
56
48
  async def test_get_balance_with_query_string(
57
49
  self, adapter, mock_token_client, mock_wallet_client
58
50
  ):
59
- """Test get_balance with query as string (auto-resolves chain_id)."""
60
51
  mock_token_client.get_token_details = AsyncMock(
61
52
  return_value={
62
53
  "token_id": "usd-coin-base",
@@ -86,7 +77,6 @@ class TestBalanceAdapter:
86
77
  async def test_get_balance_with_query_dict(
87
78
  self, adapter, mock_token_client, mock_wallet_client
88
79
  ):
89
- """get_balance accepts query= as dict with token_id key."""
90
80
  mock_token_client.get_token_details = AsyncMock(
91
81
  return_value={
92
82
  "token_id": "wsteth-base",
@@ -113,7 +103,6 @@ class TestBalanceAdapter:
113
103
 
114
104
  @pytest.mark.asyncio
115
105
  async def test_get_balance_missing_query(self, adapter):
116
- """get_balance returns error when query is empty or missing token_id."""
117
106
  success, result = await adapter.get_balance(query={}, wallet_address="0xabc")
118
107
  assert success is False
119
108
  assert "missing query" in str(result)
@@ -122,7 +111,6 @@ class TestBalanceAdapter:
122
111
  async def test_get_balance_with_pool_address(
123
112
  self, adapter, mock_token_client, mock_wallet_client
124
113
  ):
125
- """Test get_balance with pool address (explicit chain_id)"""
126
114
  mock_wallet_client.get_token_balance_for_address = AsyncMock(
127
115
  return_value={"balance": 5000000}
128
116
  )
@@ -145,7 +133,6 @@ class TestBalanceAdapter:
145
133
 
146
134
  @pytest.mark.asyncio
147
135
  async def test_get_balance_token_not_found(self, adapter, mock_token_client):
148
- """Test get_balance when token is not found"""
149
136
  mock_token_client.get_token_details = AsyncMock(return_value=None)
150
137
 
151
138
  success, error = await adapter.get_balance(
@@ -158,7 +145,6 @@ class TestBalanceAdapter:
158
145
 
159
146
  @pytest.mark.asyncio
160
147
  async def test_get_balance_missing_chain_id(self, adapter, mock_token_client):
161
- """Test get_balance when chain_id cannot be resolved"""
162
148
  mock_token_client.get_token_details = AsyncMock(
163
149
  return_value={
164
150
  "token_id": "token-without-chain",
@@ -1,247 +1,124 @@
1
1
  # BRAP Adapter
2
2
 
3
- A Wayfinder adapter that provides high-level operations for cross-chain swaps and quotes via the BRAP (Bridge/Router/Adapter Protocol). This adapter wraps the `BRAPClient` to offer strategy-friendly methods for getting quotes, comparing routes, and executing cross-chain transactions.
3
+ Adapter for cross-chain swaps and bridges via the BRAP (Bridge/Router/Adapter Protocol).
4
4
 
5
- ## Capabilities
5
+ - **Type**: `BRAP`
6
+ - **Module**: `wayfinder_paths.adapters.brap_adapter.adapter.BRAPAdapter`
6
7
 
7
- - `swap.quote`: Get quotes for cross-chain swap operations
8
- - `swap.execute`: Execute cross-chain swaps
9
- - `bridge.quote`: Get quotes for bridge operations
10
- - `bridge.execute`: Execute bridge operations
11
- - `route.optimize`: Compare and optimize routes
12
- - `fee.calculate`: Calculate fees and costs
8
+ ## Overview
13
9
 
14
- ## Configuration
15
-
16
- The BRAPClient will automatically:
17
-
18
- - Use the WAYFINDER_API_URL from settings
19
- - Handle authentication via config.json
20
- - Manage token refresh and retry logic
10
+ The BRAPAdapter provides:
11
+ - Cross-chain swap quotes
12
+ - Bridge operation quotes
13
+ - Route comparison and optimization
14
+ - Fee calculations
15
+ - Swap execution
21
16
 
22
17
  ## Usage
23
18
 
24
- ### Initialize the Adapter
25
-
26
19
  ```python
27
20
  from wayfinder_paths.adapters.brap_adapter.adapter import BRAPAdapter
28
21
 
29
22
  adapter = BRAPAdapter()
30
23
  ```
31
24
 
32
- ### Get Swap Quote
25
+ ## Methods
33
26
 
34
- ```python
35
- success, data = await adapter.get_swap_quote(
36
- from_token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
37
- to_token_address="0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
38
- from_chain_id=8453, # Base
39
- to_chain_id=1, # Ethereum
40
- from_address="0x1234567890123456789012345678901234567890",
41
- to_address="0x1234567890123456789012345678901234567890",
42
- amount="1000000000000000000", # 1 token (18 decimals)
43
- slippage=0.01 # 1% slippage
44
- )
45
- if success:
46
- quotes = data.get("quotes", {})
47
- best_quote = quotes.get("best_quote", {})
48
- print(f"Output amount: {best_quote.get('output_amount')}")
49
- print(f"Total fee: {best_quote.get('total_fee')}")
50
- else:
51
- print(f"Error: {data}")
52
- ```
27
+ ### get_swap_quote
53
28
 
54
- ### Get Best Quote
29
+ Get quotes for a cross-chain swap.
55
30
 
56
31
  ```python
57
- success, data = await adapter.get_best_quote(
58
- from_token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
59
- to_token_address="0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
32
+ success, data = await adapter.get_swap_quote(
33
+ from_token_address="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
34
+ to_token_address="0x...",
60
35
  from_chain_id=8453,
61
36
  to_chain_id=1,
62
- from_address="0x1234567890123456789012345678901234567890",
63
- to_address="0x1234567890123456789012345678901234567890",
64
- amount="1000000000000000000"
37
+ from_address="0x...",
38
+ to_address="0x...",
39
+ amount="1000000000", # Raw amount
40
+ slippage=0.01, # 1%
65
41
  )
66
42
  if success:
67
- print(f"Best output: {data.get('output_amount')}")
68
- print(f"Gas fee: {data.get('gas_fee')}")
69
- print(f"Bridge fee: {data.get('bridge_fee')}")
70
- else:
71
- print(f"Error: {data}")
43
+ best_quote = data.get("quotes", {}).get("best_quote", {})
44
+ print(f"Output: {best_quote.get('output_amount')}")
72
45
  ```
73
46
 
74
- ### Calculate Swap Fees
47
+ ### get_best_quote
75
48
 
76
- ```python
77
- success, data = await adapter.calculate_swap_fees(
78
- from_token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
79
- to_token_address="0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
80
- from_chain_id=8453,
81
- to_chain_id=1,
82
- amount="1000000000000000000",
83
- slippage=0.01
84
- )
85
- if success:
86
- print(f"Input amount: {data.get('input_amount')}")
87
- print(f"Output amount: {data.get('output_amount')}")
88
- print(f"Gas fee: {data.get('gas_fee')}")
89
- print(f"Bridge fee: {data.get('bridge_fee')}")
90
- print(f"Protocol fee: {data.get('protocol_fee')}")
91
- print(f"Total fee: {data.get('total_fee')}")
92
- print(f"Price impact: {data.get('price_impact')}")
93
- else:
94
- print(f"Error: {data}")
95
- ```
96
-
97
- ### Compare Routes
49
+ Get the best quote for a swap.
98
50
 
99
51
  ```python
100
- success, data = await adapter.compare_routes(
101
- from_token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
102
- to_token_address="0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
52
+ success, data = await adapter.get_best_quote(
53
+ from_token_address="0x...",
54
+ to_token_address="0x...",
103
55
  from_chain_id=8453,
104
56
  to_chain_id=1,
105
- amount="1000000000000000000"
106
- )
107
- if success:
108
- print(f"Total routes available: {data.get('total_routes')}")
109
- print(f"Best route output: {data.get('best_route', {}).get('output_amount')}")
110
-
111
- for i, route in enumerate(data.get('all_routes', [])):
112
- print(f"Route {i+1}: Output {route.get('output_amount')}, Fee {route.get('total_fee')}")
113
- else:
114
- print(f"Error: {data}")
115
- ```
116
-
117
- ### Estimate Gas Costs
118
-
119
- ```python
120
- success, data = await adapter.estimate_gas_cost(
121
- from_chain_id=8453, # Base
122
- to_chain_id=1, # Ethereum
123
- operation_type="swap"
57
+ from_address="0x...",
58
+ to_address="0x...",
59
+ amount="1000000000",
124
60
  )
125
- if success:
126
- print(f"From chain: {data.get('from_chain')}")
127
- print(f"To chain: {data.get('to_chain')}")
128
- print(f"From gas estimate: {data.get('from_gas_estimate')}")
129
- print(f"To gas estimate: {data.get('to_gas_estimate')}")
130
- print(f"Total operations: {data.get('total_operations')}")
131
- else:
132
- print(f"Error: {data}")
133
61
  ```
134
62
 
135
- ### Validate Swap Parameters
136
-
137
- ```python
138
- success, data = await adapter.validate_swap_parameters(
139
- from_token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
140
- to_token_address="0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
141
- from_chain_id=8453,
142
- to_chain_id=1,
143
- amount="1000000000000000000"
144
- )
145
- if success:
146
- if data.get("valid"):
147
- print("Parameters are valid")
148
- print(f"Estimated output: {data.get('estimated_output')}")
149
- else:
150
- print("Parameters are invalid:")
151
- for error in data.get("errors", []):
152
- print(f" - {error}")
153
- else:
154
- print(f"Error: {data}")
155
- ```
63
+ ### compare_routes
156
64
 
157
- ### Get Bridge Quote
65
+ Compare available routes for a swap.
158
66
 
159
67
  ```python
160
- # Bridge operations use the same interface as swaps
161
- success, data = await adapter.get_bridge_quote(
162
- from_token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
163
- to_token_address="0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
68
+ success, data = await adapter.compare_routes(
69
+ from_token_address="0x...",
70
+ to_token_address="0x...",
164
71
  from_chain_id=8453,
165
72
  to_chain_id=1,
166
- amount="1000000000000000000",
167
- slippage=0.01
73
+ amount="1000000000",
168
74
  )
169
75
  if success:
170
- print(f"Bridge quote received: {data.get('quotes', {}).get('best_quote', {}).get('output_amount')}")
171
- else:
172
- print(f"Error: {data}")
76
+ print(f"Total routes: {data.get('total_routes')}")
77
+ for route in data.get("all_routes", []):
78
+ print(f"Output: {route.get('output_amount')}, Fee: {route.get('total_fee')}")
173
79
  ```
174
80
 
175
- ## Advanced Usage
81
+ ### calculate_swap_fees
176
82
 
177
- ### Route Optimization
83
+ Calculate fees for a swap operation.
178
84
 
179
85
  ```python
180
- # Compare multiple routes to find the best option
181
- success, data = await adapter.compare_routes(
182
- from_token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
183
- to_token_address="0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
86
+ success, data = await adapter.calculate_swap_fees(
87
+ from_token_address="0x...",
88
+ to_token_address="0x...",
184
89
  from_chain_id=8453,
185
90
  to_chain_id=1,
186
- amount="1000000000000000000"
91
+ amount="1000000000",
92
+ slippage=0.01,
187
93
  )
188
-
189
94
  if success:
190
- analysis = data.get("route_analysis", {})
191
- highest_output = analysis.get("highest_output")
192
- lowest_fees = analysis.get("lowest_fees")
193
- fastest = analysis.get("fastest")
194
-
195
- print(f"Highest output route: {highest_output.get('output_amount')}")
196
- print(f"Lowest fees route: {lowest_fees.get('total_fee')}")
197
- print(f"Fastest route: {fastest.get('estimated_time')} seconds")
95
+ print(f"Gas fee: {data.get('gas_fee')}")
96
+ print(f"Bridge fee: {data.get('bridge_fee')}")
97
+ print(f"Total fee: {data.get('total_fee')}")
198
98
  ```
199
99
 
200
- ### Fee Analysis
100
+ ### validate_swap_parameters
101
+
102
+ Validate swap parameters before execution.
201
103
 
202
104
  ```python
203
- # Analyze fees for a swap operation
204
- success, data = await adapter.calculate_swap_fees(
205
- from_token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
206
- to_token_address="0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
105
+ success, data = await adapter.validate_swap_parameters(
106
+ from_token_address="0x...",
107
+ to_token_address="0x...",
207
108
  from_chain_id=8453,
208
109
  to_chain_id=1,
209
- amount="1000000000000000000"
110
+ amount="1000000000",
210
111
  )
211
-
212
- if success:
213
- input_amount = int(data.get("input_amount", 0))
214
- output_amount = int(data.get("output_amount", 0))
215
- total_fee = int(data.get("total_fee", 0))
216
-
217
- # Calculate effective rate
218
- effective_rate = (input_amount - output_amount) / input_amount
219
- print(f"Effective rate: {effective_rate:.4f} ({effective_rate * 100:.2f}%)")
220
- print(f"Total fees: {total_fee / 1e18:.6f} tokens")
112
+ if success and data.get("valid"):
113
+ print("Parameters are valid")
221
114
  ```
222
115
 
223
- ## API Endpoints
224
-
225
- The adapter uses the following Wayfinder API endpoints:
226
-
227
- - `POST /api/v1/public/quotes/` - Get swap/bridge quotes
228
-
229
- ## Error Handling
230
-
231
- All methods return a tuple of `(success: bool, data: Any)` where:
116
+ ## Dependencies
232
117
 
233
- - `success` is `True` if the operation succeeded
234
- - `data` contains the response data on success or error message on failure
118
+ - `BRAPClient` - Low-level API client
235
119
 
236
120
  ## Testing
237
121
 
238
- Run the adapter tests:
239
-
240
122
  ```bash
241
- pytest wayfinder_paths/adapters/brap_adapter/test_adapter.py -v
123
+ poetry run pytest wayfinder_paths/adapters/brap_adapter/ -v
242
124
  ```
243
-
244
- ## Dependencies
245
-
246
- - `BRAPClient` - Low-level API client for BRAP operations
247
- - `BaseAdapter` - Base adapter class with common functionality
@@ -1,7 +1,3 @@
1
- """
2
- BRAP Adapter Package
3
- """
4
-
5
1
  from .adapter import BRAPAdapter
6
2
 
7
3
  __all__ = ["BRAPAdapter"]