@agentlayer.tech/wallet 0.1.65 → 0.1.67
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/.openclaw/extensions/agent-wallet/index.ts +82 -0
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +7 -1
- package/.openclaw/extensions/agent-wallet/package.json +1 -1
- package/VERSION +1 -1
- package/agent-wallet/README.md +6 -0
- package/agent-wallet/agent_wallet/__init__.py +1 -1
- package/agent-wallet/agent_wallet/openclaw_adapter.py +485 -4
- package/agent-wallet/agent_wallet/providers/kamino.py +169 -3
- package/agent-wallet/agent_wallet/providers/x402.py +229 -148
- package/agent-wallet/agent_wallet/transaction_policy.py +60 -0
- package/agent-wallet/agent_wallet/wallet_layer/base.py +124 -0
- package/agent-wallet/agent_wallet/wallet_layer/solana.py +563 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +16 -0
- package/agent-wallet/openclaw.plugin.json +2 -2
- package/agent-wallet/pyproject.toml +1 -1
- package/agent-wallet/scripts/install_openclaw_local_config.py +6 -0
- package/agent-wallet/skills/wallet-operator/SKILL.md +6 -4
- package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +1 -1
- package/claude-code/plugins/agent-wallet/skills/wallet-operator/SKILL.md +1 -1
- package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +1 -1
- package/codex/plugins/agent-wallet/server.py +52 -3
- package/codex/plugins/agent-wallet/skills/wallet-operator/SKILL.md +1 -1
- package/hermes/plugins/agent_wallet/plugin.yaml +1 -1
- package/install-from-github.sh +6 -0
- package/package.json +1 -1
- package/wdk-btc-wallet/package.json +1 -1
- package/wdk-evm-wallet/package.json +1 -1
- package/wdk-evm-wallet/src/wdk_evm_wallet.js +126 -19
|
@@ -29,6 +29,10 @@ LEGACY_ALLOWLIST_TOOLS = [
|
|
|
29
29
|
"set_wallet_backend",
|
|
30
30
|
"get_wallet_portfolio",
|
|
31
31
|
"get_solana_token_prices",
|
|
32
|
+
"get_kamino_portfolio",
|
|
33
|
+
"get_kamino_vaults",
|
|
34
|
+
"get_kamino_earn_positions",
|
|
35
|
+
"get_kamino_liquidity_positions",
|
|
32
36
|
"get_kamino_lend_markets",
|
|
33
37
|
"get_kamino_lend_market_reserves",
|
|
34
38
|
"get_kamino_lend_user_obligations",
|
|
@@ -37,6 +41,8 @@ LEGACY_ALLOWLIST_TOOLS = [
|
|
|
37
41
|
"kamino_lend_withdraw",
|
|
38
42
|
"kamino_lend_borrow",
|
|
39
43
|
"kamino_lend_repay",
|
|
44
|
+
"kamino_earn_deposit",
|
|
45
|
+
"kamino_earn_withdraw",
|
|
40
46
|
"sign_wallet_message",
|
|
41
47
|
"transfer_sol",
|
|
42
48
|
"transfer_btc",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wallet-operator
|
|
3
|
-
description: Use
|
|
3
|
+
description: Use whenever the user's own funds are involved, even if they never say "wallet": balances, portfolio, transfers, swaps, LI.FI cross-chain swaps, Jupiter swaps, Velora EVM swaps, BTC transfers, staking, Kamino lending, Bags launches, and wallet execution safety.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Wallet Operator
|
|
@@ -30,7 +30,7 @@ Use this skill before calling OpenClaw wallet tools. It is the routing guide for
|
|
|
30
30
|
- EVM transfers: `transfer_evm_native`, `transfer_evm_token`.
|
|
31
31
|
- BTC transfer: `transfer_btc`.
|
|
32
32
|
- Solana staking: `stake_sol_native`, `deactivate_solana_stake`, `withdraw_solana_stake`.
|
|
33
|
-
- Kamino: `kamino_lend_deposit`, `kamino_lend_withdraw`, `kamino_lend_borrow`, `kamino_lend_repay`.
|
|
33
|
+
- Kamino: `get_kamino_portfolio`, `get_kamino_vaults`, `get_kamino_earn_positions`, `get_kamino_liquidity_positions`, `kamino_lend_deposit`, `kamino_lend_withdraw`, `kamino_lend_borrow`, `kamino_lend_repay`, `kamino_earn_deposit`, `kamino_earn_withdraw`.
|
|
34
34
|
- Bags: `launch_bags_token`.
|
|
35
35
|
|
|
36
36
|
## Common Token IDs
|
|
@@ -118,8 +118,10 @@ Use this skill before calling OpenClaw wallet tools. It is the routing guide for
|
|
|
118
118
|
- `stake_sol_native`: `vote_account`, `amount` in SOL, `mode`, `purpose`.
|
|
119
119
|
- `deactivate_solana_stake`: `stake_account`, `mode`, `purpose`.
|
|
120
120
|
- `withdraw_solana_stake`: `stake_account`, `amount` in SOL, optional `recipient`, `mode`, `purpose`.
|
|
121
|
-
- Before Kamino writes, use `get_kamino_lend_markets`, `get_kamino_lend_market_reserves`, `get_kamino_lend_user_obligations`, and `get_kamino_lend_user_rewards`.
|
|
122
|
-
- Kamino
|
|
121
|
+
- Before Kamino lend writes, use `get_kamino_lend_markets`, `get_kamino_lend_market_reserves`, `get_kamino_lend_user_obligations`, and `get_kamino_lend_user_rewards`.
|
|
122
|
+
- For broader Kamino read coverage, prefer `get_kamino_portfolio` first, then drill into `get_kamino_vaults`, `get_kamino_earn_positions`, or `get_kamino_liquidity_positions` as needed.
|
|
123
|
+
- Kamino lend write params: `market`, `reserve`, `amount_ui` decimal string, `mode`, `purpose`.
|
|
124
|
+
- Kamino Earn write params: `kvault`, `amount_ui` decimal string, `mode`, `purpose`.
|
|
123
125
|
- `launch_bags_token`: `name`, `symbol`, `description`, `base_mint`, `claimers`, `basis_points`, `initial_buy_sol`, `mode`, `purpose`; optional socials/image/config type.
|
|
124
126
|
- `close_empty_token_accounts`: `limit`, `mode` (`preview` or `execute`), `purpose`.
|
|
125
127
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-wallet",
|
|
3
3
|
"displayName": "Agent Wallet",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.67",
|
|
5
5
|
"description": "Claude Code bridge for the existing AgentLayer wallet runtime. Connects to Solana, Bitcoin, and EVM wallets without creating a new one.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "AgentLayer"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Use
|
|
2
|
+
description: "Use whenever the user's own funds or wallet are involved — balances, portfolio, transfers, swaps, bridging, staking, lending, or x402 payments — even if the user never says \"wallet\". Trigger phrases include \"my balance\", \"how much SOL/ETH/BTC/USDC do I have\", \"send/transfer X to\", \"swap\", \"bridge\", \"stake\", \"my portfolio\", \"pay for this API\", \"x402\". Prefer agent-wallet MCP tools over shell commands, raw RPC, or crypto data servers. Preview writes first and execute only after explicit user confirmation."
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Agent Wallet Operator
|
|
@@ -273,6 +273,44 @@ def _cache_preview_for_approval(user_id: str, tool_name: str, payload: dict[str,
|
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
|
|
276
|
+
X402_PREVIEW_REUSE_TTL_SECONDS = 300
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _cache_x402_preview_payload(user_id: str, payload: dict[str, Any]) -> None:
|
|
280
|
+
"""Cache a paid-endpoint preview so x402_pay_request can skip its unpaid probe.
|
|
281
|
+
|
|
282
|
+
x402 previews run on the read-only resident-worker path, so they never reach
|
|
283
|
+
_cache_preview_for_approval (and preview-mode annotation strips
|
|
284
|
+
confirmation_summary anyway). Stored under the x402_preview_request key that
|
|
285
|
+
the pay alias resolves to. The wallet runtime revalidates the payload by
|
|
286
|
+
request fingerprint and falls back to a fresh probe on any mismatch, so a
|
|
287
|
+
stale or unrelated cached preview can never redirect a payment.
|
|
288
|
+
"""
|
|
289
|
+
if not isinstance(payload, dict) or payload.get("ok") is False:
|
|
290
|
+
return
|
|
291
|
+
data = payload.get("data")
|
|
292
|
+
if not isinstance(data, dict):
|
|
293
|
+
return
|
|
294
|
+
if not data.get("payment_required") or not str(data.get("request_fingerprint") or "").strip():
|
|
295
|
+
return
|
|
296
|
+
with _approval_cache_lock:
|
|
297
|
+
_prune_approval_preview_cache()
|
|
298
|
+
approval_preview_cache[_approval_cache_key(user_id, "x402_preview_request")] = {
|
|
299
|
+
"digest": _preview_digest(data),
|
|
300
|
+
"expires_at": time.time() + X402_PREVIEW_REUSE_TTL_SECONDS,
|
|
301
|
+
"preview": data,
|
|
302
|
+
"summary": None,
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _attach_x402_approved_preview(tool_name: str, effective_params: dict[str, Any]) -> None:
|
|
307
|
+
if tool_name != "x402_pay_request" or "_approved_preview" in effective_params:
|
|
308
|
+
return
|
|
309
|
+
cached = _latest_cached_preview(_user_id(), tool_name)
|
|
310
|
+
if cached and isinstance(cached.get("preview"), dict):
|
|
311
|
+
effective_params["_approved_preview"] = cached["preview"]
|
|
312
|
+
|
|
313
|
+
|
|
276
314
|
def _latest_cached_preview(user_id: str, tool_name: str) -> dict[str, Any] | None:
|
|
277
315
|
with _approval_cache_lock:
|
|
278
316
|
_prune_approval_preview_cache()
|
|
@@ -1403,6 +1441,7 @@ def _invoke_wallet_tool_blocking(
|
|
|
1403
1441
|
cancellation stay responsive).
|
|
1404
1442
|
"""
|
|
1405
1443
|
used_cache, approval_args = _attach_approval_for_execute(tool_name, config, effective_params)
|
|
1444
|
+
_attach_x402_approved_preview(tool_name, effective_params)
|
|
1406
1445
|
try:
|
|
1407
1446
|
payload = _invoke_tool(
|
|
1408
1447
|
tool_name,
|
|
@@ -1413,6 +1452,10 @@ def _invoke_wallet_tool_blocking(
|
|
|
1413
1452
|
)
|
|
1414
1453
|
except Exception as exc:
|
|
1415
1454
|
raise _normalize_approval_context_error(exc) from exc
|
|
1455
|
+
if tool_name == "x402_pay_request":
|
|
1456
|
+
# The cached x402 preview quote is single-use: whether the payment
|
|
1457
|
+
# succeeded or the endpoint re-priced, the next pay must re-preview.
|
|
1458
|
+
_consume_cached_preview(_user_id(), tool_name)
|
|
1416
1459
|
_cache_preview_for_approval(_user_id(), tool_name, payload)
|
|
1417
1460
|
# A bridge-managed preview that was just executed successfully is single-use:
|
|
1418
1461
|
# drop it so a duplicate execute cannot silently re-run the operation.
|
|
@@ -1451,15 +1494,21 @@ async def _handle_wallet_tool(tool_name: str, params: dict[str, Any]) -> dict[st
|
|
|
1451
1494
|
_invoke_wallet_tool_blocking, tool_name, config, effective_params
|
|
1452
1495
|
)
|
|
1453
1496
|
|
|
1497
|
+
if tool_name == "x402_preview_request":
|
|
1498
|
+
_cache_x402_preview_payload(_user_id(), payload)
|
|
1454
1499
|
if payload.get("ok") is False:
|
|
1455
1500
|
raise RuntimeError(str(payload.get("error") or f"{tool_name} failed"))
|
|
1456
1501
|
return payload.get("data", {})
|
|
1457
1502
|
|
|
1458
1503
|
|
|
1459
1504
|
BASE_INSTRUCTIONS = (
|
|
1460
|
-
"
|
|
1461
|
-
"
|
|
1462
|
-
"
|
|
1505
|
+
"This server is the user's own local AgentLayer wallet (Solana, EVM, Bitcoin). Use its "
|
|
1506
|
+
"tools whenever the user asks about their balances, portfolio, addresses, transfers, "
|
|
1507
|
+
"swaps, bridging, staking, lending, or x402 payments — even when they never say the "
|
|
1508
|
+
"word 'wallet'. For anything touching the user's own funds, prefer these tools over "
|
|
1509
|
+
"shell commands, raw RPC calls, or other crypto data servers (those are for arbitrary "
|
|
1510
|
+
"addresses and market data, not the user's wallet). Keep wallet secrets local. Preview "
|
|
1511
|
+
"writes first when supported, and execute only after explicit user confirmation."
|
|
1463
1512
|
)
|
|
1464
1513
|
|
|
1465
1514
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "wallet-operator"
|
|
3
|
-
description: "Use
|
|
3
|
+
description: "Use whenever the user's own funds or wallet are involved — balances, portfolio, transfers, swaps, bridging, staking, lending, or x402 payments — even if the user never says \"wallet\". Trigger phrases include \"my balance\", \"how much SOL/ETH/BTC/USDC do I have\", \"send/transfer X to\", \"swap\", \"bridge\", \"stake\", \"my portfolio\". Prefer wallet tools over shell commands, preview writes first, and keep approval/signing semantics intact."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Agent Wallet Operator
|
package/install-from-github.sh
CHANGED
|
@@ -120,9 +120,15 @@ if [ -z "$SOURCE_ROOT" ] || [ ! -d "$SOURCE_ROOT" ]; then
|
|
|
120
120
|
exit 1
|
|
121
121
|
fi
|
|
122
122
|
|
|
123
|
+
# Pre-flight must be a superset of setup.sh's require_path list: everything is
|
|
124
|
+
# checked on the EXTRACTED temp tree, before the destructive swap below. A
|
|
125
|
+
# bundle that would fail setup.sh must never replace the user's runtime.
|
|
123
126
|
require_path "$SOURCE_ROOT/setup.sh" "local setup entrypoint"
|
|
124
127
|
require_path "$SOURCE_ROOT/agent-wallet" "agent-wallet package"
|
|
128
|
+
require_path "$SOURCE_ROOT/agent-wallet/scripts/install_agent_wallet.py" "Python installer"
|
|
125
129
|
require_path "$SOURCE_ROOT/.openclaw/extensions/agent-wallet" "OpenClaw extension"
|
|
130
|
+
require_path "$SOURCE_ROOT/codex/plugins/agent-wallet/.codex-plugin/plugin.json" "Codex plugin"
|
|
131
|
+
require_path "$SOURCE_ROOT/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json" "Claude Code plugin"
|
|
126
132
|
require_path "$SOURCE_ROOT/wdk-btc-wallet/package.json" "wdk-btc-wallet runtime"
|
|
127
133
|
require_path "$SOURCE_ROOT/wdk-evm-wallet/package.json" "wdk-evm-wallet runtime"
|
|
128
134
|
|
package/package.json
CHANGED
|
@@ -94,8 +94,38 @@ const LIFI_CHAIN_ALIASES = {
|
|
|
94
94
|
sol: "1151111081099710",
|
|
95
95
|
solana: "1151111081099710",
|
|
96
96
|
};
|
|
97
|
-
|
|
97
|
+
// Default is deliberately small: list responses land in an LLM agent's
|
|
98
|
+
// context window (a 100-item vault list is ~80 KB of JSON). Agents can raise
|
|
99
|
+
// the limit explicitly when they really need more.
|
|
100
|
+
const MORPHO_DEFAULT_LIST_LIMIT = 20;
|
|
98
101
|
const MORPHO_MAX_LIST_LIMIT = 500;
|
|
102
|
+
// Discovery lists/details only — never user positions. APY/TVL drift over
|
|
103
|
+
// two minutes is below the indexer's own aggregation noise.
|
|
104
|
+
const MORPHO_DISCOVERY_CACHE_TTL_MS = 120_000;
|
|
105
|
+
const MORPHO_DISCOVERY_CACHE_MAX_ENTRIES = 64;
|
|
106
|
+
const morphoDiscoveryCache = new Map();
|
|
107
|
+
|
|
108
|
+
function morphoDiscoveryCacheGet(key) {
|
|
109
|
+
const entry = morphoDiscoveryCache.get(key);
|
|
110
|
+
if (!entry) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
if (entry.expiresAt <= Date.now()) {
|
|
114
|
+
morphoDiscoveryCache.delete(key);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
return JSON.parse(entry.payload);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function morphoDiscoveryCacheSet(key, payload) {
|
|
121
|
+
if (morphoDiscoveryCache.size >= MORPHO_DISCOVERY_CACHE_MAX_ENTRIES) {
|
|
122
|
+
morphoDiscoveryCache.delete(morphoDiscoveryCache.keys().next().value);
|
|
123
|
+
}
|
|
124
|
+
morphoDiscoveryCache.set(key, {
|
|
125
|
+
expiresAt: Date.now() + MORPHO_DISCOVERY_CACHE_TTL_MS,
|
|
126
|
+
payload: JSON.stringify(payload),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
99
129
|
const MORPHO_VAULT_LIST_QUERY = `
|
|
100
130
|
query MorphoVaultV2List($first: Int!, $where: VaultV2sFilters, $orderBy: VaultV2OrderBy, $orderDirection: OrderDirection) {
|
|
101
131
|
vaultV2s(first: $first, where: $where, orderBy: $orderBy, orderDirection: $orderDirection) {
|
|
@@ -112,6 +142,7 @@ const MORPHO_VAULT_LIST_QUERY = `
|
|
|
112
142
|
idleAssets
|
|
113
143
|
idleAssetsUsd
|
|
114
144
|
sharePrice
|
|
145
|
+
netApy
|
|
115
146
|
avgNetApy
|
|
116
147
|
avgNetApyExcludingRewards
|
|
117
148
|
performanceFee
|
|
@@ -666,6 +697,17 @@ function normalizeMorphoSearch(value) {
|
|
|
666
697
|
return value.trim() || null;
|
|
667
698
|
}
|
|
668
699
|
|
|
700
|
+
function normalizeOptionalNonNegativeNumber(value, fieldName) {
|
|
701
|
+
if (value === undefined || value === null || value === "") {
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
const num = Number(value);
|
|
705
|
+
if (!Number.isFinite(num) || num < 0) {
|
|
706
|
+
throw new Error(`${fieldName} must be a non-negative number.`);
|
|
707
|
+
}
|
|
708
|
+
return num;
|
|
709
|
+
}
|
|
710
|
+
|
|
669
711
|
function normalizeOptionalAddressFilter(value, fieldName) {
|
|
670
712
|
if (value === undefined || value === null || value === "") {
|
|
671
713
|
return null;
|
|
@@ -1925,21 +1967,29 @@ export class WdkEvmWalletService {
|
|
|
1925
1967
|
limit,
|
|
1926
1968
|
listedOnly = true,
|
|
1927
1969
|
assetAddress = null,
|
|
1970
|
+
minTotalAssetsUsd = null,
|
|
1971
|
+
minNetApy = null,
|
|
1928
1972
|
orderBy,
|
|
1929
1973
|
orderDirection,
|
|
1930
1974
|
}) {
|
|
1931
1975
|
const runtimeConfig = this.#resolveRuntimeConfig(network);
|
|
1932
1976
|
assertMorphoSupportedNetwork(runtimeConfig.network);
|
|
1933
1977
|
if (vaultAddress !== null && vaultAddress !== undefined && String(vaultAddress).trim()) {
|
|
1978
|
+
const address = normalizeAddress(vaultAddress, "vaultAddress");
|
|
1979
|
+
const cacheKey = JSON.stringify(["vault", runtimeConfig.chainId, address]);
|
|
1980
|
+
const cached = morphoDiscoveryCacheGet(cacheKey);
|
|
1981
|
+
if (cached) {
|
|
1982
|
+
return cached;
|
|
1983
|
+
}
|
|
1934
1984
|
const data = await this.#morphoGraphqlRequest({
|
|
1935
1985
|
query: MORPHO_VAULT_BY_ADDRESS_QUERY,
|
|
1936
1986
|
variables: {
|
|
1937
|
-
address
|
|
1987
|
+
address,
|
|
1938
1988
|
chainId: runtimeConfig.chainId,
|
|
1939
1989
|
},
|
|
1940
1990
|
operationName: "MorphoVaultV2ByAddress",
|
|
1941
1991
|
});
|
|
1942
|
-
|
|
1992
|
+
const result = {
|
|
1943
1993
|
network: runtimeConfig.network,
|
|
1944
1994
|
chainId: runtimeConfig.chainId,
|
|
1945
1995
|
protocol: "morpho",
|
|
@@ -1947,10 +1997,17 @@ export class WdkEvmWalletService {
|
|
|
1947
1997
|
found: Boolean(data.vaultV2ByAddress),
|
|
1948
1998
|
source: "morpho-api",
|
|
1949
1999
|
};
|
|
2000
|
+
morphoDiscoveryCacheSet(cacheKey, result);
|
|
2001
|
+
return result;
|
|
1950
2002
|
}
|
|
1951
2003
|
const first = normalizeMorphoListLimit(limit);
|
|
1952
2004
|
const onlyListed = normalizeMorphoListedOnly(listedOnly);
|
|
1953
2005
|
const assetAddressFilter = normalizeOptionalAddressFilter(assetAddress, "assetAddress");
|
|
2006
|
+
const minTotalAssetsUsdFilter = normalizeOptionalNonNegativeNumber(
|
|
2007
|
+
minTotalAssetsUsd,
|
|
2008
|
+
"minTotalAssetsUsd"
|
|
2009
|
+
);
|
|
2010
|
+
const minNetApyFilter = normalizeOptionalNonNegativeNumber(minNetApy, "minNetApy");
|
|
1954
2011
|
const resolvedOrderBy = normalizeMorphoOrderBy(
|
|
1955
2012
|
orderBy,
|
|
1956
2013
|
MORPHO_VAULT_ORDER_LOOKUP,
|
|
@@ -1964,18 +2021,30 @@ export class WdkEvmWalletService {
|
|
|
1964
2021
|
if (assetAddressFilter) {
|
|
1965
2022
|
where.assetAddress_in = assetAddressFilter;
|
|
1966
2023
|
}
|
|
2024
|
+
if (minTotalAssetsUsdFilter !== null) {
|
|
2025
|
+
where.totalAssetsUsd_gte = minTotalAssetsUsdFilter;
|
|
2026
|
+
}
|
|
2027
|
+
if (minNetApyFilter !== null) {
|
|
2028
|
+
where.netApy_gte = minNetApyFilter;
|
|
2029
|
+
}
|
|
2030
|
+
const variables = {
|
|
2031
|
+
first,
|
|
2032
|
+
where,
|
|
2033
|
+
orderBy: resolvedOrderBy,
|
|
2034
|
+
orderDirection: resolvedOrderDirection,
|
|
2035
|
+
};
|
|
2036
|
+
const cacheKey = JSON.stringify(["vaults", variables]);
|
|
2037
|
+
const cached = morphoDiscoveryCacheGet(cacheKey);
|
|
2038
|
+
if (cached) {
|
|
2039
|
+
return cached;
|
|
2040
|
+
}
|
|
1967
2041
|
const data = await this.#morphoGraphqlRequest({
|
|
1968
2042
|
query: MORPHO_VAULT_LIST_QUERY,
|
|
1969
|
-
variables
|
|
1970
|
-
first,
|
|
1971
|
-
where,
|
|
1972
|
-
orderBy: resolvedOrderBy,
|
|
1973
|
-
orderDirection: resolvedOrderDirection,
|
|
1974
|
-
},
|
|
2043
|
+
variables,
|
|
1975
2044
|
operationName: "MorphoVaultV2List",
|
|
1976
2045
|
});
|
|
1977
2046
|
const vaults = Array.isArray(data?.vaultV2s?.items) ? data.vaultV2s.items : [];
|
|
1978
|
-
|
|
2047
|
+
const result = {
|
|
1979
2048
|
network: runtimeConfig.network,
|
|
1980
2049
|
chainId: runtimeConfig.chainId,
|
|
1981
2050
|
protocol: "morpho",
|
|
@@ -1984,10 +2053,14 @@ export class WdkEvmWalletService {
|
|
|
1984
2053
|
orderBy: resolvedOrderBy,
|
|
1985
2054
|
orderDirection: resolvedOrderDirection,
|
|
1986
2055
|
assetAddressFilter,
|
|
2056
|
+
minTotalAssetsUsd: minTotalAssetsUsdFilter,
|
|
2057
|
+
minNetApy: minNetApyFilter,
|
|
1987
2058
|
vaultCount: vaults.length,
|
|
1988
2059
|
vaults,
|
|
1989
2060
|
source: "morpho-api",
|
|
1990
2061
|
};
|
|
2062
|
+
morphoDiscoveryCacheSet(cacheKey, result);
|
|
2063
|
+
return result;
|
|
1991
2064
|
}
|
|
1992
2065
|
|
|
1993
2066
|
async getMorphoMarkets({
|
|
@@ -1998,21 +2071,29 @@ export class WdkEvmWalletService {
|
|
|
1998
2071
|
search,
|
|
1999
2072
|
collateralAssetAddress = null,
|
|
2000
2073
|
loanAssetAddress = null,
|
|
2074
|
+
minSupplyAssetsUsd = null,
|
|
2075
|
+
minNetSupplyApy = null,
|
|
2001
2076
|
orderBy,
|
|
2002
2077
|
orderDirection,
|
|
2003
2078
|
}) {
|
|
2004
2079
|
const runtimeConfig = this.#resolveRuntimeConfig(network);
|
|
2005
2080
|
assertMorphoSupportedNetwork(runtimeConfig.network);
|
|
2006
2081
|
if (marketId !== null && marketId !== undefined && String(marketId).trim()) {
|
|
2082
|
+
const normalizedMarketId = assertMorphoMarketId(marketId, "marketId");
|
|
2083
|
+
const cacheKey = JSON.stringify(["market", runtimeConfig.chainId, normalizedMarketId]);
|
|
2084
|
+
const cached = morphoDiscoveryCacheGet(cacheKey);
|
|
2085
|
+
if (cached) {
|
|
2086
|
+
return cached;
|
|
2087
|
+
}
|
|
2007
2088
|
const data = await this.#morphoGraphqlRequest({
|
|
2008
2089
|
query: MORPHO_MARKET_BY_ID_QUERY,
|
|
2009
2090
|
variables: {
|
|
2010
|
-
marketId:
|
|
2091
|
+
marketId: normalizedMarketId,
|
|
2011
2092
|
chainId: runtimeConfig.chainId,
|
|
2012
2093
|
},
|
|
2013
2094
|
operationName: "MorphoMarketById",
|
|
2014
2095
|
});
|
|
2015
|
-
|
|
2096
|
+
const result = {
|
|
2016
2097
|
network: runtimeConfig.network,
|
|
2017
2098
|
chainId: runtimeConfig.chainId,
|
|
2018
2099
|
protocol: "morpho",
|
|
@@ -2020,6 +2101,8 @@ export class WdkEvmWalletService {
|
|
|
2020
2101
|
found: Boolean(data.marketById),
|
|
2021
2102
|
source: "morpho-api",
|
|
2022
2103
|
};
|
|
2104
|
+
morphoDiscoveryCacheSet(cacheKey, result);
|
|
2105
|
+
return result;
|
|
2023
2106
|
}
|
|
2024
2107
|
const first = normalizeMorphoListLimit(limit);
|
|
2025
2108
|
const onlyListed = normalizeMorphoListedOnly(listedOnly);
|
|
@@ -2029,6 +2112,14 @@ export class WdkEvmWalletService {
|
|
|
2029
2112
|
"collateralAssetAddress"
|
|
2030
2113
|
);
|
|
2031
2114
|
const loanFilter = normalizeOptionalAddressFilter(loanAssetAddress, "loanAssetAddress");
|
|
2115
|
+
const minSupplyAssetsUsdFilter = normalizeOptionalNonNegativeNumber(
|
|
2116
|
+
minSupplyAssetsUsd,
|
|
2117
|
+
"minSupplyAssetsUsd"
|
|
2118
|
+
);
|
|
2119
|
+
const minNetSupplyApyFilter = normalizeOptionalNonNegativeNumber(
|
|
2120
|
+
minNetSupplyApy,
|
|
2121
|
+
"minNetSupplyApy"
|
|
2122
|
+
);
|
|
2032
2123
|
const resolvedOrderBy = normalizeMorphoOrderBy(
|
|
2033
2124
|
orderBy,
|
|
2034
2125
|
MORPHO_MARKET_ORDER_LOOKUP,
|
|
@@ -2048,18 +2139,30 @@ export class WdkEvmWalletService {
|
|
|
2048
2139
|
if (loanFilter) {
|
|
2049
2140
|
where.loanAssetAddress_in = loanFilter;
|
|
2050
2141
|
}
|
|
2142
|
+
if (minSupplyAssetsUsdFilter !== null) {
|
|
2143
|
+
where.supplyAssetsUsd_gte = minSupplyAssetsUsdFilter;
|
|
2144
|
+
}
|
|
2145
|
+
if (minNetSupplyApyFilter !== null) {
|
|
2146
|
+
where.netSupplyApy_gte = minNetSupplyApyFilter;
|
|
2147
|
+
}
|
|
2148
|
+
const variables = {
|
|
2149
|
+
first,
|
|
2150
|
+
where,
|
|
2151
|
+
orderBy: resolvedOrderBy,
|
|
2152
|
+
orderDirection: resolvedOrderDirection,
|
|
2153
|
+
};
|
|
2154
|
+
const cacheKey = JSON.stringify(["markets", variables]);
|
|
2155
|
+
const cached = morphoDiscoveryCacheGet(cacheKey);
|
|
2156
|
+
if (cached) {
|
|
2157
|
+
return cached;
|
|
2158
|
+
}
|
|
2051
2159
|
const data = await this.#morphoGraphqlRequest({
|
|
2052
2160
|
query: MORPHO_MARKET_LIST_QUERY,
|
|
2053
|
-
variables
|
|
2054
|
-
first,
|
|
2055
|
-
where,
|
|
2056
|
-
orderBy: resolvedOrderBy,
|
|
2057
|
-
orderDirection: resolvedOrderDirection,
|
|
2058
|
-
},
|
|
2161
|
+
variables,
|
|
2059
2162
|
operationName: "MorphoMarketList",
|
|
2060
2163
|
});
|
|
2061
2164
|
const markets = Array.isArray(data?.markets?.items) ? data.markets.items : [];
|
|
2062
|
-
|
|
2165
|
+
const result = {
|
|
2063
2166
|
network: runtimeConfig.network,
|
|
2064
2167
|
chainId: runtimeConfig.chainId,
|
|
2065
2168
|
protocol: "morpho",
|
|
@@ -2070,10 +2173,14 @@ export class WdkEvmWalletService {
|
|
|
2070
2173
|
search: searchTerm,
|
|
2071
2174
|
collateralAssetFilter: collateralFilter,
|
|
2072
2175
|
loanAssetFilter: loanFilter,
|
|
2176
|
+
minSupplyAssetsUsd: minSupplyAssetsUsdFilter,
|
|
2177
|
+
minNetSupplyApy: minNetSupplyApyFilter,
|
|
2073
2178
|
marketCount: markets.length,
|
|
2074
2179
|
markets,
|
|
2075
2180
|
source: "morpho-api",
|
|
2076
2181
|
};
|
|
2182
|
+
morphoDiscoveryCacheSet(cacheKey, result);
|
|
2183
|
+
return result;
|
|
2077
2184
|
}
|
|
2078
2185
|
|
|
2079
2186
|
async getMorphoPositions({ seedPhrase, address, accountIndex = 0, network }) {
|