wayfinder-paths 0.1.1__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.
- wayfinder_paths/CONFIG_GUIDE.md +394 -0
- wayfinder_paths/__init__.py +21 -0
- wayfinder_paths/config.example.json +20 -0
- wayfinder_paths/conftest.py +31 -0
- wayfinder_paths/core/__init__.py +13 -0
- wayfinder_paths/core/adapters/BaseAdapter.py +48 -0
- wayfinder_paths/core/adapters/__init__.py +5 -0
- wayfinder_paths/core/adapters/base.py +5 -0
- wayfinder_paths/core/clients/AuthClient.py +83 -0
- wayfinder_paths/core/clients/BRAPClient.py +90 -0
- wayfinder_paths/core/clients/ClientManager.py +231 -0
- wayfinder_paths/core/clients/HyperlendClient.py +151 -0
- wayfinder_paths/core/clients/LedgerClient.py +222 -0
- wayfinder_paths/core/clients/PoolClient.py +96 -0
- wayfinder_paths/core/clients/SimulationClient.py +180 -0
- wayfinder_paths/core/clients/TokenClient.py +73 -0
- wayfinder_paths/core/clients/TransactionClient.py +47 -0
- wayfinder_paths/core/clients/WalletClient.py +90 -0
- wayfinder_paths/core/clients/WayfinderClient.py +258 -0
- wayfinder_paths/core/clients/__init__.py +48 -0
- wayfinder_paths/core/clients/protocols.py +295 -0
- wayfinder_paths/core/clients/sdk_example.py +115 -0
- wayfinder_paths/core/config.py +369 -0
- wayfinder_paths/core/constants/__init__.py +26 -0
- wayfinder_paths/core/constants/base.py +25 -0
- wayfinder_paths/core/constants/erc20_abi.py +118 -0
- wayfinder_paths/core/constants/hyperlend_abi.py +152 -0
- wayfinder_paths/core/engine/VaultJob.py +182 -0
- wayfinder_paths/core/engine/__init__.py +5 -0
- wayfinder_paths/core/engine/manifest.py +97 -0
- wayfinder_paths/core/services/__init__.py +0 -0
- wayfinder_paths/core/services/base.py +177 -0
- wayfinder_paths/core/services/local_evm_txn.py +429 -0
- wayfinder_paths/core/services/local_token_txn.py +231 -0
- wayfinder_paths/core/services/web3_service.py +45 -0
- wayfinder_paths/core/settings.py +61 -0
- wayfinder_paths/core/strategies/Strategy.py +183 -0
- wayfinder_paths/core/strategies/__init__.py +5 -0
- wayfinder_paths/core/strategies/base.py +7 -0
- wayfinder_paths/core/utils/__init__.py +1 -0
- wayfinder_paths/core/utils/evm_helpers.py +165 -0
- wayfinder_paths/core/utils/wallets.py +77 -0
- wayfinder_paths/core/wallets/README.md +91 -0
- wayfinder_paths/core/wallets/WalletManager.py +56 -0
- wayfinder_paths/core/wallets/__init__.py +7 -0
- wayfinder_paths/run_strategy.py +409 -0
- wayfinder_paths/scripts/__init__.py +0 -0
- wayfinder_paths/scripts/create_strategy.py +181 -0
- wayfinder_paths/scripts/make_wallets.py +160 -0
- wayfinder_paths/scripts/validate_manifests.py +213 -0
- wayfinder_paths/tests/__init__.py +0 -0
- wayfinder_paths/tests/test_smoke_manifest.py +48 -0
- wayfinder_paths/tests/test_test_coverage.py +212 -0
- wayfinder_paths/tests/test_utils.py +64 -0
- wayfinder_paths/vaults/__init__.py +0 -0
- wayfinder_paths/vaults/adapters/__init__.py +0 -0
- wayfinder_paths/vaults/adapters/balance_adapter/README.md +104 -0
- wayfinder_paths/vaults/adapters/balance_adapter/adapter.py +257 -0
- wayfinder_paths/vaults/adapters/balance_adapter/examples.json +6 -0
- wayfinder_paths/vaults/adapters/balance_adapter/manifest.yaml +8 -0
- wayfinder_paths/vaults/adapters/balance_adapter/test_adapter.py +83 -0
- wayfinder_paths/vaults/adapters/brap_adapter/README.md +249 -0
- wayfinder_paths/vaults/adapters/brap_adapter/__init__.py +7 -0
- wayfinder_paths/vaults/adapters/brap_adapter/adapter.py +717 -0
- wayfinder_paths/vaults/adapters/brap_adapter/examples.json +175 -0
- wayfinder_paths/vaults/adapters/brap_adapter/manifest.yaml +11 -0
- wayfinder_paths/vaults/adapters/brap_adapter/test_adapter.py +288 -0
- wayfinder_paths/vaults/adapters/hyperlend_adapter/__init__.py +7 -0
- wayfinder_paths/vaults/adapters/hyperlend_adapter/adapter.py +298 -0
- wayfinder_paths/vaults/adapters/hyperlend_adapter/manifest.yaml +10 -0
- wayfinder_paths/vaults/adapters/hyperlend_adapter/test_adapter.py +267 -0
- wayfinder_paths/vaults/adapters/ledger_adapter/README.md +158 -0
- wayfinder_paths/vaults/adapters/ledger_adapter/__init__.py +7 -0
- wayfinder_paths/vaults/adapters/ledger_adapter/adapter.py +286 -0
- wayfinder_paths/vaults/adapters/ledger_adapter/examples.json +131 -0
- wayfinder_paths/vaults/adapters/ledger_adapter/manifest.yaml +11 -0
- wayfinder_paths/vaults/adapters/ledger_adapter/test_adapter.py +202 -0
- wayfinder_paths/vaults/adapters/pool_adapter/README.md +218 -0
- wayfinder_paths/vaults/adapters/pool_adapter/__init__.py +7 -0
- wayfinder_paths/vaults/adapters/pool_adapter/adapter.py +289 -0
- wayfinder_paths/vaults/adapters/pool_adapter/examples.json +143 -0
- wayfinder_paths/vaults/adapters/pool_adapter/manifest.yaml +10 -0
- wayfinder_paths/vaults/adapters/pool_adapter/test_adapter.py +222 -0
- wayfinder_paths/vaults/adapters/token_adapter/README.md +101 -0
- wayfinder_paths/vaults/adapters/token_adapter/__init__.py +3 -0
- wayfinder_paths/vaults/adapters/token_adapter/adapter.py +92 -0
- wayfinder_paths/vaults/adapters/token_adapter/examples.json +26 -0
- wayfinder_paths/vaults/adapters/token_adapter/manifest.yaml +6 -0
- wayfinder_paths/vaults/adapters/token_adapter/test_adapter.py +135 -0
- wayfinder_paths/vaults/strategies/__init__.py +0 -0
- wayfinder_paths/vaults/strategies/config.py +85 -0
- wayfinder_paths/vaults/strategies/hyperlend_stable_yield_strategy/README.md +99 -0
- wayfinder_paths/vaults/strategies/hyperlend_stable_yield_strategy/examples.json +16 -0
- wayfinder_paths/vaults/strategies/hyperlend_stable_yield_strategy/manifest.yaml +7 -0
- wayfinder_paths/vaults/strategies/hyperlend_stable_yield_strategy/strategy.py +2328 -0
- wayfinder_paths/vaults/strategies/hyperlend_stable_yield_strategy/test_strategy.py +319 -0
- wayfinder_paths/vaults/strategies/stablecoin_yield_strategy/README.md +95 -0
- wayfinder_paths/vaults/strategies/stablecoin_yield_strategy/examples.json +17 -0
- wayfinder_paths/vaults/strategies/stablecoin_yield_strategy/manifest.yaml +17 -0
- wayfinder_paths/vaults/strategies/stablecoin_yield_strategy/strategy.py +1684 -0
- wayfinder_paths/vaults/strategies/stablecoin_yield_strategy/test_strategy.py +350 -0
- wayfinder_paths/vaults/templates/adapter/README.md +105 -0
- wayfinder_paths/vaults/templates/adapter/adapter.py +26 -0
- wayfinder_paths/vaults/templates/adapter/examples.json +8 -0
- wayfinder_paths/vaults/templates/adapter/manifest.yaml +6 -0
- wayfinder_paths/vaults/templates/adapter/test_adapter.py +49 -0
- wayfinder_paths/vaults/templates/strategy/README.md +152 -0
- wayfinder_paths/vaults/templates/strategy/examples.json +11 -0
- wayfinder_paths/vaults/templates/strategy/manifest.yaml +8 -0
- wayfinder_paths/vaults/templates/strategy/strategy.py +57 -0
- wayfinder_paths/vaults/templates/strategy/test_strategy.py +197 -0
- wayfinder_paths-0.1.1.dist-info/LICENSE +21 -0
- wayfinder_paths-0.1.1.dist-info/METADATA +727 -0
- wayfinder_paths-0.1.1.dist-info/RECORD +115 -0
- wayfinder_paths-0.1.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
from unittest.mock import AsyncMock, patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from wayfinder_paths.vaults.adapters.ledger_adapter.adapter import LedgerAdapter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestLedgerAdapter:
|
|
9
|
+
"""Test cases for LedgerAdapter"""
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def mock_ledger_client(self):
|
|
13
|
+
"""Mock LedgerClient for testing"""
|
|
14
|
+
mock_client = AsyncMock()
|
|
15
|
+
return mock_client
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def adapter(self, mock_ledger_client):
|
|
19
|
+
"""Create a LedgerAdapter instance with mocked client for testing"""
|
|
20
|
+
with patch(
|
|
21
|
+
"vaults.adapters.ledger_adapter.adapter.LedgerClient",
|
|
22
|
+
return_value=mock_ledger_client,
|
|
23
|
+
):
|
|
24
|
+
return LedgerAdapter()
|
|
25
|
+
|
|
26
|
+
@pytest.mark.asyncio
|
|
27
|
+
async def test_get_vault_transactions_success(self, adapter, mock_ledger_client):
|
|
28
|
+
"""Test successful vault transaction retrieval"""
|
|
29
|
+
mock_response = {
|
|
30
|
+
"transactions": [
|
|
31
|
+
{
|
|
32
|
+
"id": "tx_123",
|
|
33
|
+
"operation": "DEPOSIT",
|
|
34
|
+
"amount": "1000000000000000000",
|
|
35
|
+
"usd_value": "1000.00",
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"total": 1,
|
|
39
|
+
}
|
|
40
|
+
mock_ledger_client.get_vault_transactions = AsyncMock(
|
|
41
|
+
return_value=mock_response
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
success, data = await adapter.get_vault_transactions(
|
|
45
|
+
wallet_address="0x1234567890123456789012345678901234567890",
|
|
46
|
+
limit=10,
|
|
47
|
+
offset=0,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
assert success is True
|
|
51
|
+
assert data == mock_response
|
|
52
|
+
mock_ledger_client.get_vault_transactions.assert_called_once_with(
|
|
53
|
+
wallet_address="0x1234567890123456789012345678901234567890",
|
|
54
|
+
limit=10,
|
|
55
|
+
offset=0,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
@pytest.mark.asyncio
|
|
59
|
+
async def test_get_vault_transactions_failure(self, adapter, mock_ledger_client):
|
|
60
|
+
"""Test vault transaction retrieval failure"""
|
|
61
|
+
mock_ledger_client.get_vault_transactions = AsyncMock(
|
|
62
|
+
side_effect=Exception("API Error")
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
success, data = await adapter.get_vault_transactions(
|
|
66
|
+
wallet_address="0x1234567890123456789012345678901234567890"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
assert success is False
|
|
70
|
+
assert "API Error" in data
|
|
71
|
+
|
|
72
|
+
@pytest.mark.asyncio
|
|
73
|
+
async def test_get_vault_net_deposit_success(self, adapter, mock_ledger_client):
|
|
74
|
+
"""Test successful vault net deposit retrieval"""
|
|
75
|
+
mock_response = {
|
|
76
|
+
"net_deposit": "1000.00",
|
|
77
|
+
"total_deposits": "1500.00",
|
|
78
|
+
"total_withdrawals": "500.00",
|
|
79
|
+
}
|
|
80
|
+
mock_ledger_client.get_vault_net_deposit = AsyncMock(return_value=mock_response)
|
|
81
|
+
|
|
82
|
+
# Test
|
|
83
|
+
success, data = await adapter.get_vault_net_deposit(
|
|
84
|
+
wallet_address="0x1234567890123456789012345678901234567890"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
assert success is True
|
|
88
|
+
assert data == mock_response
|
|
89
|
+
mock_ledger_client.get_vault_net_deposit.assert_called_once_with(
|
|
90
|
+
wallet_address="0x1234567890123456789012345678901234567890"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
@pytest.mark.asyncio
|
|
94
|
+
async def test_record_deposit_success(self, adapter, mock_ledger_client):
|
|
95
|
+
"""Test successful deposit recording"""
|
|
96
|
+
mock_response = {
|
|
97
|
+
"transaction_id": "tx_456",
|
|
98
|
+
"status": "recorded",
|
|
99
|
+
"timestamp": "2024-01-15T10:30:00Z",
|
|
100
|
+
}
|
|
101
|
+
mock_ledger_client.add_vault_deposit.return_value = mock_response
|
|
102
|
+
|
|
103
|
+
# Test
|
|
104
|
+
success, data = await adapter.record_deposit(
|
|
105
|
+
wallet_address="0x1234567890123456789012345678901234567890",
|
|
106
|
+
chain_id=8453,
|
|
107
|
+
token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
|
|
108
|
+
token_amount="1000000000000000000",
|
|
109
|
+
usd_value="1000.00",
|
|
110
|
+
strategy_name="TestStrategy",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
assert success is True
|
|
114
|
+
assert data == mock_response
|
|
115
|
+
mock_ledger_client.add_vault_deposit.assert_called_once_with(
|
|
116
|
+
wallet_address="0x1234567890123456789012345678901234567890",
|
|
117
|
+
chain_id=8453,
|
|
118
|
+
token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
|
|
119
|
+
token_amount="1000000000000000000",
|
|
120
|
+
usd_value="1000.00",
|
|
121
|
+
data=None,
|
|
122
|
+
strategy_name="TestStrategy",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
@pytest.mark.asyncio
|
|
126
|
+
async def test_record_withdrawal_success(self, adapter, mock_ledger_client):
|
|
127
|
+
"""Test successful withdrawal recording"""
|
|
128
|
+
mock_response = {
|
|
129
|
+
"transaction_id": "tx_789",
|
|
130
|
+
"status": "recorded",
|
|
131
|
+
"timestamp": "2024-01-15T11:00:00Z",
|
|
132
|
+
}
|
|
133
|
+
mock_ledger_client.add_vault_withdraw.return_value = mock_response
|
|
134
|
+
|
|
135
|
+
# Test
|
|
136
|
+
success, data = await adapter.record_withdrawal(
|
|
137
|
+
wallet_address="0x1234567890123456789012345678901234567890",
|
|
138
|
+
chain_id=8453,
|
|
139
|
+
token_address="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
|
|
140
|
+
token_amount="500000000000000000",
|
|
141
|
+
usd_value="500.00",
|
|
142
|
+
strategy_name="TestStrategy",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
assert success is True
|
|
146
|
+
assert data == mock_response
|
|
147
|
+
|
|
148
|
+
@pytest.mark.asyncio
|
|
149
|
+
async def test_record_operation_success(self, adapter, mock_ledger_client):
|
|
150
|
+
"""Test successful operation recording"""
|
|
151
|
+
mock_response = {
|
|
152
|
+
"operation_id": "op_123",
|
|
153
|
+
"status": "recorded",
|
|
154
|
+
"timestamp": "2024-01-15T10:45:00Z",
|
|
155
|
+
}
|
|
156
|
+
mock_ledger_client.add_vault_operation.return_value = mock_response
|
|
157
|
+
|
|
158
|
+
# Test
|
|
159
|
+
operation_data = {
|
|
160
|
+
"type": "SWAP",
|
|
161
|
+
"from_token": "0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
|
|
162
|
+
"to_token": "0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
|
|
163
|
+
"amount_in": "1000000000000000000",
|
|
164
|
+
"amount_out": "995000000000000000",
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
success, data = await adapter.record_operation(
|
|
168
|
+
wallet_address="0x1234567890123456789012345678901234567890",
|
|
169
|
+
operation_data=operation_data,
|
|
170
|
+
usd_value="1000.00",
|
|
171
|
+
strategy_name="TestStrategy",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
assert success is True
|
|
175
|
+
assert data == mock_response
|
|
176
|
+
|
|
177
|
+
@pytest.mark.asyncio
|
|
178
|
+
async def test_get_transaction_summary_success(self, adapter, mock_ledger_client):
|
|
179
|
+
"""Test successful transaction summary generation"""
|
|
180
|
+
mock_transactions = {
|
|
181
|
+
"transactions": [
|
|
182
|
+
{"operation": "DEPOSIT", "amount": "1000000000000000000"},
|
|
183
|
+
{"operation": "WITHDRAW", "amount": "500000000000000000"},
|
|
184
|
+
{"operation": "SWAP", "amount": "200000000000000000"},
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
mock_ledger_client.get_vault_transactions.return_value = mock_transactions
|
|
188
|
+
|
|
189
|
+
# Test
|
|
190
|
+
success, data = await adapter.get_transaction_summary(
|
|
191
|
+
wallet_address="0x1234567890123456789012345678901234567890", limit=10
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
assert success is True
|
|
195
|
+
assert data["total_transactions"] == 3
|
|
196
|
+
assert data["operations"]["deposits"] == 1
|
|
197
|
+
assert data["operations"]["withdrawals"] == 1
|
|
198
|
+
assert data["operations"]["operations"] == 1
|
|
199
|
+
|
|
200
|
+
def test_adapter_type(self, adapter):
|
|
201
|
+
"""Test adapter has adapter_type"""
|
|
202
|
+
assert adapter.adapter_type == "LEDGER"
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Pool Adapter
|
|
2
|
+
|
|
3
|
+
A Wayfinder adapter that provides high-level operations for DeFi pool data and analytics. This adapter wraps the `PoolClient` to offer strategy-friendly methods for discovering, analyzing, and filtering yield opportunities.
|
|
4
|
+
|
|
5
|
+
## Capabilities
|
|
6
|
+
|
|
7
|
+
- `pool.read`: Read pool information and metadata
|
|
8
|
+
- `pool.analytics`: Get comprehensive pool analytics
|
|
9
|
+
- `pool.discovery`: Find and search pools
|
|
10
|
+
- `llama.data`: Access Llama protocol data
|
|
11
|
+
- `pool.reports`: Get pool reports and analytics
|
|
12
|
+
|
|
13
|
+
## Configuration
|
|
14
|
+
|
|
15
|
+
The adapter uses the PoolClient which automatically handles authentication and API configuration through the Wayfinder settings. No additional configuration is required.
|
|
16
|
+
|
|
17
|
+
The PoolClient will automatically:
|
|
18
|
+
- Use the WAYFINDER_API_URL from settings
|
|
19
|
+
- Handle authentication via environment variables or config.json
|
|
20
|
+
- Manage token refresh and retry logic
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Initialize the Adapter
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from wayfinder_paths.vaults.adapters.pool_adapter.adapter import PoolAdapter
|
|
28
|
+
|
|
29
|
+
# No configuration needed - uses PoolClient with automatic settings
|
|
30
|
+
adapter = PoolAdapter()
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Get Pools by IDs
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
success, data = await adapter.get_pools_by_ids(
|
|
37
|
+
pool_ids=["pool-123", "pool-456"],
|
|
38
|
+
merge_external=True
|
|
39
|
+
)
|
|
40
|
+
if success:
|
|
41
|
+
pools = data.get("pools", [])
|
|
42
|
+
print(f"Found {len(pools)} pools")
|
|
43
|
+
else:
|
|
44
|
+
print(f"Error: {data}")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Get All Pools
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
success, data = await adapter.get_all_pools(merge_external=False)
|
|
51
|
+
if success:
|
|
52
|
+
pools = data.get("pools", [])
|
|
53
|
+
print(f"Total pools available: {len(pools)}")
|
|
54
|
+
else:
|
|
55
|
+
print(f"Error: {data}")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Get Combined Pool Reports
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
success, data = await adapter.get_combined_pool_reports()
|
|
62
|
+
if success:
|
|
63
|
+
reports = data.get("reports", [])
|
|
64
|
+
print(f"Received {len(reports)} combined reports")
|
|
65
|
+
else:
|
|
66
|
+
print(f"Error: {data}")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Find High Yield Pools
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
success, data = await adapter.find_high_yield_pools(
|
|
73
|
+
min_apy=0.03, # 3% minimum APY
|
|
74
|
+
min_tvl=500000, # $500k minimum TVL
|
|
75
|
+
stablecoin_only=True,
|
|
76
|
+
network_codes=["base", "ethereum"]
|
|
77
|
+
)
|
|
78
|
+
if success:
|
|
79
|
+
pools = data.get("pools", [])
|
|
80
|
+
print(f"Found {len(pools)} high-yield pools")
|
|
81
|
+
for pool in pools:
|
|
82
|
+
print(f"Pool: {pool.get('id')} - APY: {pool.get('llama_apy_pct')}%")
|
|
83
|
+
else:
|
|
84
|
+
print(f"Error: {data}")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Get Pool Analytics
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
success, data = await adapter.get_pool_analytics(
|
|
91
|
+
pool_ids=["pool-123", "pool-456"]
|
|
92
|
+
)
|
|
93
|
+
if success:
|
|
94
|
+
analytics = data.get("analytics", [])
|
|
95
|
+
for pool_analytics in analytics:
|
|
96
|
+
pool = pool_analytics.get("pool", {})
|
|
97
|
+
combined_apy = pool_analytics.get("combined_apy", 0)
|
|
98
|
+
tvl_usd = pool_analytics.get("tvl_usd", 0)
|
|
99
|
+
print(f"Pool: {pool.get('name')} - APY: {combined_apy:.2%} - TVL: ${tvl_usd:,.0f}")
|
|
100
|
+
else:
|
|
101
|
+
print(f"Error: {data}")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Search Pools
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
success, data = await adapter.search_pools(
|
|
108
|
+
query="USDC",
|
|
109
|
+
limit=10
|
|
110
|
+
)
|
|
111
|
+
if success:
|
|
112
|
+
pools = data.get("pools", [])
|
|
113
|
+
print(f"Found {len(pools)} pools matching 'USDC'")
|
|
114
|
+
for pool in pools:
|
|
115
|
+
print(f"Pool: {pool.get('name')} - {pool.get('symbol')}")
|
|
116
|
+
else:
|
|
117
|
+
print(f"Error: {data}")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Get Llama Matches
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
success, data = await adapter.get_llama_matches()
|
|
124
|
+
if success:
|
|
125
|
+
matches = data.get("matches", [])
|
|
126
|
+
print(f"Found {len(matches)} Llama matches")
|
|
127
|
+
for match in matches:
|
|
128
|
+
if match.get("llama_stablecoin"):
|
|
129
|
+
print(f"Stablecoin pool: {match.get('id')} - APY: {match.get('llama_apy_pct')}%")
|
|
130
|
+
else:
|
|
131
|
+
print(f"Error: {data}")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Get Llama Reports
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
success, data = await adapter.get_llama_reports(
|
|
138
|
+
identifiers=["pool-123", "usd-coin-base", "base_0x1234..."]
|
|
139
|
+
)
|
|
140
|
+
if success:
|
|
141
|
+
reports = data
|
|
142
|
+
for identifier, report in reports.items():
|
|
143
|
+
print(f"Report for {identifier}: APY {report.get('llama_apy_pct', 0)}%")
|
|
144
|
+
else:
|
|
145
|
+
print(f"Error: {data}")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Advanced Usage
|
|
149
|
+
|
|
150
|
+
### Filtering High Yield Pools
|
|
151
|
+
|
|
152
|
+
The `find_high_yield_pools` method provides powerful filtering capabilities:
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
# Find stablecoin pools with high yield on specific networks
|
|
156
|
+
success, data = await adapter.find_high_yield_pools(
|
|
157
|
+
min_apy=0.05, # 5% minimum APY
|
|
158
|
+
min_tvl=1000000, # $1M minimum TVL
|
|
159
|
+
stablecoin_only=True, # Only stablecoin pools
|
|
160
|
+
network_codes=["base", "arbitrum"] # Specific networks
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if success:
|
|
164
|
+
pools = data.get("pools", [])
|
|
165
|
+
# Pools are automatically sorted by APY (highest first)
|
|
166
|
+
best_pool = pools[0] if pools else None
|
|
167
|
+
if best_pool:
|
|
168
|
+
print(f"Best pool: {best_pool.get('id')} - APY: {best_pool.get('llama_apy_pct')}%")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Comprehensive Pool Analysis
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
# Get detailed analytics for specific pools
|
|
175
|
+
success, data = await adapter.get_pool_analytics(["pool-123"])
|
|
176
|
+
|
|
177
|
+
if success:
|
|
178
|
+
analytics = data.get("analytics", [])
|
|
179
|
+
for pool_analytics in analytics:
|
|
180
|
+
pool = pool_analytics.get("pool", {})
|
|
181
|
+
llama_data = pool_analytics.get("llama_data", {})
|
|
182
|
+
|
|
183
|
+
print(f"Pool: {pool.get('name')}")
|
|
184
|
+
print(f" Combined APY: {pool_analytics.get('combined_apy', 0):.2%}")
|
|
185
|
+
print(f" TVL: ${pool_analytics.get('tvl_usd', 0):,.0f}")
|
|
186
|
+
print(f" Llama APY: {llama_data.get('llama_apy_pct', 0)}%")
|
|
187
|
+
print(f" Stablecoin: {llama_data.get('llama_stablecoin', False)}")
|
|
188
|
+
print(f" IL Risk: {llama_data.get('llama_il_risk', 'unknown')}")
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## API Endpoints
|
|
192
|
+
|
|
193
|
+
The adapter uses the following Wayfinder API endpoints:
|
|
194
|
+
|
|
195
|
+
- `GET /api/v1/public/pools/?pool_ids=X` - Get pools by IDs
|
|
196
|
+
- `GET /api/v1/public/pools/` - Get all pools
|
|
197
|
+
- `GET /api/v1/public/pools/combined/` - Get combined pool reports
|
|
198
|
+
- `GET /api/v1/public/pools/llama/matches/` - Get Llama matches
|
|
199
|
+
- `GET /api/v1/public/pools/llama/reports/` - Get Llama reports
|
|
200
|
+
|
|
201
|
+
## Error Handling
|
|
202
|
+
|
|
203
|
+
All methods return a tuple of `(success: bool, data: Any)` where:
|
|
204
|
+
- `success` is `True` if the operation succeeded
|
|
205
|
+
- `data` contains the response data on success or error message on failure
|
|
206
|
+
|
|
207
|
+
## Testing
|
|
208
|
+
|
|
209
|
+
Run the adapter tests:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
pytest wayfinder_paths/vaults/adapters/pool_adapter/test_adapter.py -v
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Dependencies
|
|
216
|
+
|
|
217
|
+
- `PoolClient` - Low-level API client for pool operations
|
|
218
|
+
- `BaseAdapter` - Base adapter class with common functionality
|