@agentlayer.tech/wallet 0.1.93 → 0.1.95
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/dist/index.js +79 -0
- package/.openclaw/extensions/agent-wallet/index.ts +79 -0
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +6 -1
- package/.openclaw/extensions/agent-wallet/package.json +1 -1
- package/CHANGELOG.md +18 -0
- package/VERSION +1 -1
- package/agent-wallet/agent_wallet/__init__.py +1 -1
- package/agent-wallet/agent_wallet/autonomous_permissions.py +1 -0
- package/agent-wallet/agent_wallet/openclaw_adapter.py +262 -0
- package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +2 -0
- package/agent-wallet/agent_wallet/wallet_layer/base.py +37 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +157 -0
- package/agent-wallet/openclaw.plugin.json +1 -1
- package/agent-wallet/pyproject.toml +1 -1
- package/agent-wallet/scripts/install_agent_wallet.py +29 -1
- package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +1 -1
- package/claude-code/plugins/agent-wallet/AGENTLAYER_AGENT_GUIDE.md +282 -0
- package/claude-code/plugins/agent-wallet/README.md +2 -0
- package/claude-code/plugins/agent-wallet/commands/guide.md +40 -0
- package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +1 -1
- package/codex/plugins/agent-wallet/server.py +1 -0
- package/hermes/plugins/agent_wallet/plugin.yaml +1 -1
- package/package.json +1 -1
- package/wdk-btc-wallet/package.json +1 -1
- package/wdk-evm-wallet/.env.example +3 -0
- package/wdk-evm-wallet/README.md +6 -0
- package/wdk-evm-wallet/package.json +1 -1
- package/wdk-evm-wallet/src/config.js +9 -0
- package/wdk-evm-wallet/src/server.js +24 -0
- package/wdk-evm-wallet/src/wdk_evm_wallet.js +469 -0
|
@@ -29,6 +29,7 @@ const AUTONOMOUS_DEFI_TOOLS = new Set([
|
|
|
29
29
|
"manage_evm_lido_withdrawal",
|
|
30
30
|
"manage_evm_morpho_market_position",
|
|
31
31
|
"manage_evm_morpho_vault_position",
|
|
32
|
+
"manage_evm_uniswap_liquidity",
|
|
32
33
|
]);
|
|
33
34
|
const approvalPreviewCache = new Map();
|
|
34
35
|
const WALLET_TOOL_ONLY_GUIDANCE =
|
|
@@ -1977,6 +1978,61 @@ const evmToolDefinitions = [
|
|
|
1977
1978
|
additionalProperties: false,
|
|
1978
1979
|
},
|
|
1979
1980
|
},
|
|
1981
|
+
{
|
|
1982
|
+
name: "search_uniswap_pairs",
|
|
1983
|
+
description: "Search read-only onchain Uniswap-tradeable pairs by name, ticker, or ERC-20 address. Verify any returned token address independently before quoting or trading.",
|
|
1984
|
+
parameters: {
|
|
1985
|
+
type: "object",
|
|
1986
|
+
properties: {
|
|
1987
|
+
query: { type: "string" },
|
|
1988
|
+
token_address: { type: "string" },
|
|
1989
|
+
chain: { type: "string" },
|
|
1990
|
+
dex_id: { type: "string" },
|
|
1991
|
+
all_chains: { type: "boolean" },
|
|
1992
|
+
limit: { type: "integer" },
|
|
1993
|
+
network: { type: "string", enum: EVM_CORE_NETWORKS },
|
|
1994
|
+
},
|
|
1995
|
+
additionalProperties: false,
|
|
1996
|
+
},
|
|
1997
|
+
},
|
|
1998
|
+
{
|
|
1999
|
+
name: "get_evm_uniswap_pools",
|
|
2000
|
+
description: "Find existing Uniswap V3/V4 pools through the official Pool Info API on ethereum, base, or robinhood. Returns the canonical poolReferenceIdentifier needed for an LP create request. Read-only: it does not approve, sign, or execute anything.",
|
|
2001
|
+
parameters: {
|
|
2002
|
+
type: "object",
|
|
2003
|
+
properties: {
|
|
2004
|
+
protocol: { type: "string", enum: ["V3", "V4"] },
|
|
2005
|
+
pool_parameters: {
|
|
2006
|
+
type: "object",
|
|
2007
|
+
description: "Official Pool Info API token-pair parameters, such as tokenAddressA, tokenAddressB and optional fee/tickSpacing/hooks.",
|
|
2008
|
+
additionalProperties: true,
|
|
2009
|
+
},
|
|
2010
|
+
pool_references: {
|
|
2011
|
+
type: "array",
|
|
2012
|
+
maxItems: 20,
|
|
2013
|
+
items: { type: "object", additionalProperties: true },
|
|
2014
|
+
},
|
|
2015
|
+
page_size: { type: "integer", minimum: 1, maximum: 20 },
|
|
2016
|
+
current_page: { type: "integer", minimum: 1 },
|
|
2017
|
+
network: { type: "string", enum: EVM_CORE_NETWORKS },
|
|
2018
|
+
},
|
|
2019
|
+
required: ["protocol"],
|
|
2020
|
+
additionalProperties: false,
|
|
2021
|
+
},
|
|
2022
|
+
},
|
|
2023
|
+
{
|
|
2024
|
+
name: "get_evm_uniswap_positions",
|
|
2025
|
+
description: "List the active wallet's Uniswap V3 LP NFTs on ethereum, base, or robinhood. Returns token ids, token pair, fee tier, ticks, liquidity, and owed fees. Read-only. V4 is excluded because its PositionManager is not enumerable without a verified indexed source.",
|
|
2026
|
+
parameters: {
|
|
2027
|
+
type: "object",
|
|
2028
|
+
properties: {
|
|
2029
|
+
protocol: { type: "string", enum: ["V3"] },
|
|
2030
|
+
limit: { type: "integer", minimum: 1, maximum: 100 },
|
|
2031
|
+
network: { type: "string", enum: EVM_CORE_NETWORKS },
|
|
2032
|
+
},
|
|
2033
|
+
additionalProperties: false,
|
|
2034
|
+
},
|
|
2035
|
+
},
|
|
1980
2036
|
{
|
|
1981
2037
|
name: "swap_evm_uniswap_tokens",
|
|
1982
2038
|
description: "Preview, prepare, or execute a supported Uniswap path on ethereum, base, or robinhood: CLASSIC, UniswapX orders, or canonical ETH↔WETH wrap/unwrap. ERC-20 paths may use Permit2 EIP-712 or an UniswapX order signature. Preview or prepare first. After the user explicitly confirms the shown summary in chat, call execute; the OpenClaw plugin handles the internal execution authorization automatically.",
|
|
@@ -1997,6 +2053,29 @@ const evmToolDefinitions = [
|
|
|
1997
2053
|
additionalProperties: false,
|
|
1998
2054
|
},
|
|
1999
2055
|
},
|
|
2056
|
+
{
|
|
2057
|
+
name: "manage_evm_uniswap_liquidity",
|
|
2058
|
+
description: "Preview, prepare, or execute a Uniswap V3/V4 liquidity action on ethereum, base, or robinhood. Supported actions are create, increase, decrease, and claim_fees. Create needs existingPool.poolReference and position actions need an NFT token id: use get_evm_uniswap_pools or the V3 get_evm_uniswap_positions scanner to obtain them, never guess. The official Liquidity API builds the transaction again immediately before signing, so confirmation is scoped to the LP intent rather than fragile ticks or calldata.",
|
|
2059
|
+
optional: true,
|
|
2060
|
+
parameters: {
|
|
2061
|
+
type: "object",
|
|
2062
|
+
properties: {
|
|
2063
|
+
action: { type: "string", enum: ["create", "increase", "decrease", "claim_fees"] },
|
|
2064
|
+
protocol: { type: "string", enum: ["V3", "V4"] },
|
|
2065
|
+
request: {
|
|
2066
|
+
type: "object",
|
|
2067
|
+
description: "Official Uniswap Liquidity API fields. walletAddress, chainId, protocol, simulateTransaction, and permit/signature fields are controlled by the wallet.",
|
|
2068
|
+
additionalProperties: true,
|
|
2069
|
+
},
|
|
2070
|
+
mode: { type: "string", enum: ["preview", "prepare", "execute"] },
|
|
2071
|
+
purpose: { type: "string" },
|
|
2072
|
+
user_intent: { type: "boolean" },
|
|
2073
|
+
network: { type: "string", enum: EVM_CORE_NETWORKS },
|
|
2074
|
+
},
|
|
2075
|
+
required: ["action", "protocol", "request", "mode", "purpose"],
|
|
2076
|
+
additionalProperties: false,
|
|
2077
|
+
},
|
|
2078
|
+
},
|
|
2000
2079
|
{
|
|
2001
2080
|
name: "swap_evm_lifi_cross_chain_tokens",
|
|
2002
2081
|
description: "Preview, prepare, or execute an EVM-origin cross-chain swap through LI.FI. This currently supports ethereum/base as the source network and ethereum/base/solana as the destination chain. Preview or prepare first. After the user explicitly confirms the shown summary in chat, call execute; the OpenClaw plugin handles the internal execution authorization automatically.",
|
|
@@ -29,6 +29,7 @@ const AUTONOMOUS_DEFI_TOOLS = new Set([
|
|
|
29
29
|
"manage_evm_lido_withdrawal",
|
|
30
30
|
"manage_evm_morpho_market_position",
|
|
31
31
|
"manage_evm_morpho_vault_position",
|
|
32
|
+
"manage_evm_uniswap_liquidity",
|
|
32
33
|
]);
|
|
33
34
|
const approvalPreviewCache = new Map();
|
|
34
35
|
const WALLET_TOOL_ONLY_GUIDANCE =
|
|
@@ -1977,6 +1978,61 @@ const evmToolDefinitions = [
|
|
|
1977
1978
|
additionalProperties: false,
|
|
1978
1979
|
},
|
|
1979
1980
|
},
|
|
1981
|
+
{
|
|
1982
|
+
name: "search_uniswap_pairs",
|
|
1983
|
+
description: "Search read-only onchain Uniswap-tradeable pairs by name, ticker, or ERC-20 address. Verify any returned token address independently before quoting or trading.",
|
|
1984
|
+
parameters: {
|
|
1985
|
+
type: "object",
|
|
1986
|
+
properties: {
|
|
1987
|
+
query: { type: "string" },
|
|
1988
|
+
token_address: { type: "string" },
|
|
1989
|
+
chain: { type: "string" },
|
|
1990
|
+
dex_id: { type: "string" },
|
|
1991
|
+
all_chains: { type: "boolean" },
|
|
1992
|
+
limit: { type: "integer" },
|
|
1993
|
+
network: { type: "string", enum: EVM_CORE_NETWORKS },
|
|
1994
|
+
},
|
|
1995
|
+
additionalProperties: false,
|
|
1996
|
+
},
|
|
1997
|
+
},
|
|
1998
|
+
{
|
|
1999
|
+
name: "get_evm_uniswap_pools",
|
|
2000
|
+
description: "Find existing Uniswap V3/V4 pools through the official Pool Info API on ethereum, base, or robinhood. Returns the canonical poolReferenceIdentifier needed for an LP create request. Read-only: it does not approve, sign, or execute anything.",
|
|
2001
|
+
parameters: {
|
|
2002
|
+
type: "object",
|
|
2003
|
+
properties: {
|
|
2004
|
+
protocol: { type: "string", enum: ["V3", "V4"] },
|
|
2005
|
+
pool_parameters: {
|
|
2006
|
+
type: "object",
|
|
2007
|
+
description: "Official Pool Info API token-pair parameters, such as tokenAddressA, tokenAddressB and optional fee/tickSpacing/hooks.",
|
|
2008
|
+
additionalProperties: true,
|
|
2009
|
+
},
|
|
2010
|
+
pool_references: {
|
|
2011
|
+
type: "array",
|
|
2012
|
+
maxItems: 20,
|
|
2013
|
+
items: { type: "object", additionalProperties: true },
|
|
2014
|
+
},
|
|
2015
|
+
page_size: { type: "integer", minimum: 1, maximum: 20 },
|
|
2016
|
+
current_page: { type: "integer", minimum: 1 },
|
|
2017
|
+
network: { type: "string", enum: EVM_CORE_NETWORKS },
|
|
2018
|
+
},
|
|
2019
|
+
required: ["protocol"],
|
|
2020
|
+
additionalProperties: false,
|
|
2021
|
+
},
|
|
2022
|
+
},
|
|
2023
|
+
{
|
|
2024
|
+
name: "get_evm_uniswap_positions",
|
|
2025
|
+
description: "List the active wallet's Uniswap V3 LP NFTs on ethereum, base, or robinhood. Returns token ids, token pair, fee tier, ticks, liquidity, and owed fees. Read-only. V4 is excluded because its PositionManager is not enumerable without a verified indexed source.",
|
|
2026
|
+
parameters: {
|
|
2027
|
+
type: "object",
|
|
2028
|
+
properties: {
|
|
2029
|
+
protocol: { type: "string", enum: ["V3"] },
|
|
2030
|
+
limit: { type: "integer", minimum: 1, maximum: 100 },
|
|
2031
|
+
network: { type: "string", enum: EVM_CORE_NETWORKS },
|
|
2032
|
+
},
|
|
2033
|
+
additionalProperties: false,
|
|
2034
|
+
},
|
|
2035
|
+
},
|
|
1980
2036
|
{
|
|
1981
2037
|
name: "swap_evm_uniswap_tokens",
|
|
1982
2038
|
description: "Preview, prepare, or execute a supported Uniswap path on ethereum, base, or robinhood: CLASSIC, UniswapX orders, or canonical ETH↔WETH wrap/unwrap. ERC-20 paths may use Permit2 EIP-712 or an UniswapX order signature. Preview or prepare first. After the user explicitly confirms the shown summary in chat, call execute; the OpenClaw plugin handles the internal execution authorization automatically.",
|
|
@@ -1997,6 +2053,29 @@ const evmToolDefinitions = [
|
|
|
1997
2053
|
additionalProperties: false,
|
|
1998
2054
|
},
|
|
1999
2055
|
},
|
|
2056
|
+
{
|
|
2057
|
+
name: "manage_evm_uniswap_liquidity",
|
|
2058
|
+
description: "Preview, prepare, or execute a Uniswap V3/V4 liquidity action on ethereum, base, or robinhood. Supported actions are create, increase, decrease, and claim_fees. Create needs existingPool.poolReference and position actions need an NFT token id: use get_evm_uniswap_pools or the V3 get_evm_uniswap_positions scanner to obtain them, never guess. The official Liquidity API builds the transaction again immediately before signing, so confirmation is scoped to the LP intent rather than fragile ticks or calldata.",
|
|
2059
|
+
optional: true,
|
|
2060
|
+
parameters: {
|
|
2061
|
+
type: "object",
|
|
2062
|
+
properties: {
|
|
2063
|
+
action: { type: "string", enum: ["create", "increase", "decrease", "claim_fees"] },
|
|
2064
|
+
protocol: { type: "string", enum: ["V3", "V4"] },
|
|
2065
|
+
request: {
|
|
2066
|
+
type: "object",
|
|
2067
|
+
description: "Official Uniswap Liquidity API fields. walletAddress, chainId, protocol, simulateTransaction, and permit/signature fields are controlled by the wallet.",
|
|
2068
|
+
additionalProperties: true,
|
|
2069
|
+
},
|
|
2070
|
+
mode: { type: "string", enum: ["preview", "prepare", "execute"] },
|
|
2071
|
+
purpose: { type: "string" },
|
|
2072
|
+
user_intent: { type: "boolean" },
|
|
2073
|
+
network: { type: "string", enum: EVM_CORE_NETWORKS },
|
|
2074
|
+
},
|
|
2075
|
+
required: ["action", "protocol", "request", "mode", "purpose"],
|
|
2076
|
+
additionalProperties: false,
|
|
2077
|
+
},
|
|
2078
|
+
},
|
|
2000
2079
|
{
|
|
2001
2080
|
name: "swap_evm_lifi_cross_chain_tokens",
|
|
2002
2081
|
description: "Preview, prepare, or execute an EVM-origin cross-chain swap through LI.FI. This currently supports ethereum/base as the source network and ethereum/base/solana as the destination chain. Preview or prepare first. After the user explicitly confirms the shown summary in chat, call execute; the OpenClaw plugin handles the internal execution authorization automatically.",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "agent-wallet",
|
|
3
3
|
"name": "Agent Wallet",
|
|
4
4
|
"description": "Official OpenClaw plugin bridge for the agent-wallet backends, including Solana, local BTC, and local EVM.",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.95",
|
|
6
6
|
"contracts": {
|
|
7
7
|
"tools": [
|
|
8
8
|
"agentlayer_autonomous_approve",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"get_evm_token_balance",
|
|
31
31
|
"get_evm_token_metadata",
|
|
32
32
|
"get_evm_transaction_receipt",
|
|
33
|
+
"get_uniswap_swap_quote",
|
|
33
34
|
"get_flash_trade_markets",
|
|
34
35
|
"get_flash_trade_positions",
|
|
35
36
|
"get_kamino_earn_positions",
|
|
@@ -61,11 +62,15 @@
|
|
|
61
62
|
"manage_evm_morpho_vault_position",
|
|
62
63
|
"manage_evm_lido_position",
|
|
63
64
|
"manage_evm_lido_withdrawal",
|
|
65
|
+
"manage_evm_uniswap_liquidity",
|
|
64
66
|
"search_uniswap_pairs",
|
|
67
|
+
"get_evm_uniswap_pools",
|
|
68
|
+
"get_evm_uniswap_positions",
|
|
65
69
|
"set_evm_network",
|
|
66
70
|
"set_wallet_backend",
|
|
67
71
|
"sign_wallet_message",
|
|
68
72
|
"swap_evm_lifi_cross_chain_tokens",
|
|
73
|
+
"swap_evm_uniswap_tokens",
|
|
69
74
|
"swap_evm_tokens",
|
|
70
75
|
"swap_solana_lifi_cross_chain_tokens",
|
|
71
76
|
"swap_solana_tokens",
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## v0.1.94 - 2026-08-13
|
|
6
|
+
|
|
7
|
+
- **Added Uniswap V3/V4 liquidity provisioning for Ethereum, Base, and
|
|
8
|
+
Robinhood Chain.** The EVM wallet now previews, prepares, and executes
|
|
9
|
+
create, increase, decrease, and fee-claim actions through Uniswap's
|
|
10
|
+
Liquidity API. Final LP calldata is refreshed and simulated immediately
|
|
11
|
+
before signing; executable transactions are accepted only for pinned
|
|
12
|
+
PositionManager deployments and matching wallet/network fields.
|
|
13
|
+
- **Added bounded LP approval handling and intent-safe confirmations.** Token
|
|
14
|
+
approvals are restricted to LP-request assets and approved spenders, while
|
|
15
|
+
confirmations bind the action, network, protocol, pool/position, and assets
|
|
16
|
+
rather than fast-expiring ticks or calldata. Single-sided concentrated
|
|
17
|
+
positions with a zero amount on one ERC-20 side no longer fail approval
|
|
18
|
+
discovery.
|
|
19
|
+
- **Exposed LP actions through the provider gateway, OpenClaw, and Codex.**
|
|
20
|
+
The provider gateway forwards the existing shared Uniswap API key to the
|
|
21
|
+
Liquidity API; OpenClaw's pair-search contract was restored and registered.
|
|
22
|
+
|
|
5
23
|
## v0.1.93 - 2026-08-10
|
|
6
24
|
|
|
7
25
|
- **Added `/cards` (Claude Code) and `cards` (Codex) for Laso Finance card
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.95
|
|
@@ -751,6 +751,28 @@ class OpenClawWalletAdapter:
|
|
|
751
751
|
"quote_fingerprint": provided_fingerprint,
|
|
752
752
|
}
|
|
753
753
|
|
|
754
|
+
if asset_type == "evm-uniswap-liquidity":
|
|
755
|
+
request = payload.get("request") if isinstance(payload.get("request"), dict) else {}
|
|
756
|
+
existing_pool = request.get("existingPool") if isinstance(request.get("existingPool"), dict) else {}
|
|
757
|
+
return {
|
|
758
|
+
"operation": action_label,
|
|
759
|
+
"network": str(payload.get("network") or getattr(self.backend, "network", "unknown")),
|
|
760
|
+
"from_address": payload.get("from_address"),
|
|
761
|
+
"protocol": payload.get("protocol"),
|
|
762
|
+
"liquidity_action": payload.get("liquidity_action"),
|
|
763
|
+
"liquidity_protocol": payload.get("liquidity_protocol"),
|
|
764
|
+
# Intent binds to the action and caller-provided LP scope, not a
|
|
765
|
+
# per-block transaction hash, adjusted ticks, or calculated amount.
|
|
766
|
+
"token0_address": request.get("token0Address") or existing_pool.get("token0Address"),
|
|
767
|
+
"token1_address": request.get("token1Address") or existing_pool.get("token1Address"),
|
|
768
|
+
"pool_reference": existing_pool.get("poolReference"),
|
|
769
|
+
"position_token_id": request.get("nftTokenId") or request.get("tokenId") or payload.get("position_token_id"),
|
|
770
|
+
"independent_token": request.get("independentToken"),
|
|
771
|
+
"liquidity_percentage_to_decrease": request.get("liquidityPercentageToDecrease"),
|
|
772
|
+
"slippage_tolerance": request.get("slippageTolerance"),
|
|
773
|
+
"position_manager": payload.get("position_manager"),
|
|
774
|
+
}
|
|
775
|
+
|
|
754
776
|
if asset_type == "evm-morpho-vault":
|
|
755
777
|
return {
|
|
756
778
|
"operation": action_label,
|
|
@@ -1722,6 +1744,85 @@ class OpenClawWalletAdapter:
|
|
|
1722
1744
|
risk_level="low",
|
|
1723
1745
|
),
|
|
1724
1746
|
)
|
|
1747
|
+
tools.insert(
|
|
1748
|
+
13,
|
|
1749
|
+
AgentToolSpec(
|
|
1750
|
+
name="get_evm_uniswap_pools",
|
|
1751
|
+
description=(
|
|
1752
|
+
"Find existing Uniswap V3/V4 pool metadata on ethereum, base, or robinhood using the official "
|
|
1753
|
+
"Uniswap Pool Info API. Returns the canonical poolReferenceIdentifier required to create liquidity; "
|
|
1754
|
+
"this is read-only and does not approve, sign, or execute anything."
|
|
1755
|
+
),
|
|
1756
|
+
input_schema={
|
|
1757
|
+
"type": "object",
|
|
1758
|
+
"properties": {
|
|
1759
|
+
"protocol": {"type": "string", "enum": ["V3", "V4"]},
|
|
1760
|
+
"pool_parameters": {"type": "object", "description": "Official Pool Info API token-pair parameters, such as tokenAddressA, tokenAddressB and optional fee/tickSpacing/hooks.", "additionalProperties": True},
|
|
1761
|
+
"pool_references": {"type": "array", "maxItems": 20, "items": {"type": "object", "additionalProperties": True}, "description": "One to twenty official Pool Info API pool reference objects."},
|
|
1762
|
+
"page_size": {"type": "integer", "minimum": 1, "maximum": 20},
|
|
1763
|
+
"current_page": {"type": "integer", "minimum": 1},
|
|
1764
|
+
"network": {"type": "string", "enum": ["ethereum", "base", "robinhood"]},
|
|
1765
|
+
},
|
|
1766
|
+
"required": ["protocol"],
|
|
1767
|
+
"additionalProperties": False,
|
|
1768
|
+
},
|
|
1769
|
+
read_only=True,
|
|
1770
|
+
risk_level="low",
|
|
1771
|
+
),
|
|
1772
|
+
)
|
|
1773
|
+
tools.insert(
|
|
1774
|
+
14,
|
|
1775
|
+
AgentToolSpec(
|
|
1776
|
+
name="get_evm_uniswap_positions",
|
|
1777
|
+
description=(
|
|
1778
|
+
"List read-only Uniswap V3 LP position NFTs owned by the active wallet on ethereum, base, or robinhood. "
|
|
1779
|
+
"Returns NFT token ids, tokens, fee tier, tick range, liquidity, and currently owed fees. V4 discovery is "
|
|
1780
|
+
"not exposed until a verified indexed source is configured because V4 PositionManager is not enumerable."
|
|
1781
|
+
),
|
|
1782
|
+
input_schema={
|
|
1783
|
+
"type": "object",
|
|
1784
|
+
"properties": {
|
|
1785
|
+
"protocol": {"type": "string", "enum": ["V3"], "description": "V3 is the currently enumerable, on-chain-supported position scanner."},
|
|
1786
|
+
"limit": {"type": "integer", "minimum": 1, "maximum": 100},
|
|
1787
|
+
"network": {"type": "string", "enum": ["ethereum", "base", "robinhood"]},
|
|
1788
|
+
},
|
|
1789
|
+
"additionalProperties": False,
|
|
1790
|
+
},
|
|
1791
|
+
read_only=True,
|
|
1792
|
+
risk_level="low",
|
|
1793
|
+
),
|
|
1794
|
+
)
|
|
1795
|
+
tools.insert(
|
|
1796
|
+
15,
|
|
1797
|
+
AgentToolSpec(
|
|
1798
|
+
name="manage_evm_uniswap_liquidity",
|
|
1799
|
+
description=(
|
|
1800
|
+
"Preview, prepare, or execute a Uniswap V3/V4 liquidity action on ethereum, base, or robinhood. "
|
|
1801
|
+
"Supported actions are create, increase, decrease, and claim_fees. The request is passed to the "
|
|
1802
|
+
"official Uniswap Liquidity API; execute refreshes the transaction immediately before signing. "
|
|
1803
|
+
"Create requires existingPool.poolReference; increase/decrease/claim_fees require a position NFT token id. "
|
|
1804
|
+
"Use get_evm_uniswap_pools or get_evm_uniswap_positions to obtain these identifiers; never guess them."
|
|
1805
|
+
),
|
|
1806
|
+
input_schema={
|
|
1807
|
+
"type": "object",
|
|
1808
|
+
"properties": {
|
|
1809
|
+
"action": {"type": "string", "enum": ["create", "increase", "decrease", "claim_fees"]},
|
|
1810
|
+
"protocol": {"type": "string", "enum": ["V3", "V4"]},
|
|
1811
|
+
"request": {"type": "object", "description": "Uniswap LP API fields excluding walletAddress, chainId, protocol, and simulateTransaction; those are set from the active wallet.", "additionalProperties": True},
|
|
1812
|
+
"mode": {"type": "string", "enum": ["preview", "prepare", "execute"]},
|
|
1813
|
+
"purpose": {"type": "string"},
|
|
1814
|
+
"user_intent": {"type": "boolean"},
|
|
1815
|
+
"approval_token": {"type": "string"},
|
|
1816
|
+
"network": {"type": "string", "enum": ["ethereum", "base", "robinhood"]},
|
|
1817
|
+
},
|
|
1818
|
+
"required": ["action", "protocol", "request", "mode", "purpose"],
|
|
1819
|
+
"additionalProperties": False,
|
|
1820
|
+
},
|
|
1821
|
+
read_only=False,
|
|
1822
|
+
requires_explicit_user_intent=True,
|
|
1823
|
+
risk_level="high",
|
|
1824
|
+
),
|
|
1825
|
+
)
|
|
1725
1826
|
tools.insert(
|
|
1726
1827
|
14,
|
|
1727
1828
|
AgentToolSpec(
|
|
@@ -5631,6 +5732,46 @@ class OpenClawWalletAdapter:
|
|
|
5631
5732
|
)
|
|
5632
5733
|
return AgentToolResult(tool=tool_name, ok=True, data=data)
|
|
5633
5734
|
|
|
5735
|
+
if tool_name == "get_evm_uniswap_pools":
|
|
5736
|
+
protocol = args.get("protocol")
|
|
5737
|
+
pool_parameters = args.get("pool_parameters")
|
|
5738
|
+
pool_references = args.get("pool_references")
|
|
5739
|
+
page_size = args.get("page_size", 20)
|
|
5740
|
+
current_page = args.get("current_page", 1)
|
|
5741
|
+
if protocol not in {"V3", "V4"}:
|
|
5742
|
+
raise WalletBackendError("protocol must be V3 or V4.")
|
|
5743
|
+
if (pool_parameters is None) == (pool_references is None):
|
|
5744
|
+
raise WalletBackendError("Provide exactly one of pool_parameters or pool_references.")
|
|
5745
|
+
if pool_parameters is not None and not isinstance(pool_parameters, dict):
|
|
5746
|
+
raise WalletBackendError("pool_parameters must be an object.")
|
|
5747
|
+
if pool_references is not None:
|
|
5748
|
+
if not isinstance(pool_references, list) or not 1 <= len(pool_references) <= 20:
|
|
5749
|
+
raise WalletBackendError("pool_references must contain between 1 and 20 objects.")
|
|
5750
|
+
if any(not isinstance(reference, dict) for reference in pool_references):
|
|
5751
|
+
raise WalletBackendError("pool_references must contain only objects.")
|
|
5752
|
+
if not isinstance(page_size, int) or not 1 <= page_size <= 20:
|
|
5753
|
+
raise WalletBackendError("page_size must be an integer between 1 and 20.")
|
|
5754
|
+
if not isinstance(current_page, int) or current_page < 1:
|
|
5755
|
+
raise WalletBackendError("current_page must be a positive integer.")
|
|
5756
|
+
data = await active_backend.get_uniswap_liquidity_pools(
|
|
5757
|
+
protocol=protocol,
|
|
5758
|
+
pool_parameters=pool_parameters,
|
|
5759
|
+
pool_references=pool_references,
|
|
5760
|
+
page_size=page_size,
|
|
5761
|
+
current_page=current_page,
|
|
5762
|
+
)
|
|
5763
|
+
return AgentToolResult(tool=tool_name, ok=True, data=data)
|
|
5764
|
+
|
|
5765
|
+
if tool_name == "get_evm_uniswap_positions":
|
|
5766
|
+
protocol = args.get("protocol", "V3")
|
|
5767
|
+
limit = args.get("limit", 20)
|
|
5768
|
+
if protocol != "V3":
|
|
5769
|
+
raise WalletBackendError("Only V3 position discovery is currently available; V4 PositionManager is not enumerable.")
|
|
5770
|
+
if not isinstance(limit, int) or not 1 <= limit <= 100:
|
|
5771
|
+
raise WalletBackendError("limit must be an integer between 1 and 100.")
|
|
5772
|
+
data = await active_backend.get_uniswap_liquidity_positions(protocol=protocol, limit=limit)
|
|
5773
|
+
return AgentToolResult(tool=tool_name, ok=True, data=data)
|
|
5774
|
+
|
|
5634
5775
|
if tool_name == "swap_evm_uniswap_tokens":
|
|
5635
5776
|
token_in = args.get("token_in")
|
|
5636
5777
|
token_out = args.get("token_out")
|
|
@@ -5757,6 +5898,127 @@ class OpenClawWalletAdapter:
|
|
|
5757
5898
|
),
|
|
5758
5899
|
)
|
|
5759
5900
|
|
|
5901
|
+
if tool_name == "manage_evm_uniswap_liquidity":
|
|
5902
|
+
action = args.get("action")
|
|
5903
|
+
protocol = args.get("protocol")
|
|
5904
|
+
request = args.get("request")
|
|
5905
|
+
mode = args.get("mode")
|
|
5906
|
+
purpose = args.get("purpose")
|
|
5907
|
+
user_intent = args.get("user_intent", False)
|
|
5908
|
+
approval_token = args.get("approval_token")
|
|
5909
|
+
if action not in {"create", "increase", "decrease", "claim_fees"}:
|
|
5910
|
+
raise WalletBackendError("action must be create, increase, decrease, or claim_fees.")
|
|
5911
|
+
if protocol not in {"V3", "V4"}:
|
|
5912
|
+
raise WalletBackendError("protocol must be V3 or V4.")
|
|
5913
|
+
if not isinstance(request, dict):
|
|
5914
|
+
raise WalletBackendError("request must be an object.")
|
|
5915
|
+
if mode not in {"preview", "prepare", "execute"}:
|
|
5916
|
+
raise WalletBackendError("mode must be 'preview', 'prepare' or 'execute'.")
|
|
5917
|
+
if not isinstance(purpose, str) or not purpose.strip():
|
|
5918
|
+
raise WalletBackendError("purpose is required.")
|
|
5919
|
+
normalized_request = dict(request)
|
|
5920
|
+
if action == "create":
|
|
5921
|
+
existing_pool = normalized_request.get("existingPool")
|
|
5922
|
+
if not isinstance(existing_pool, dict):
|
|
5923
|
+
raise WalletBackendError(
|
|
5924
|
+
"create requires existingPool with token0Address, token1Address, and poolReference. "
|
|
5925
|
+
"Use get_evm_uniswap_pools to obtain the exact existing pool; do not infer it from market search data."
|
|
5926
|
+
)
|
|
5927
|
+
missing_pool_fields = [
|
|
5928
|
+
field
|
|
5929
|
+
for field in ("token0Address", "token1Address", "poolReference")
|
|
5930
|
+
if not isinstance(existing_pool.get(field), str) or not existing_pool[field].strip()
|
|
5931
|
+
]
|
|
5932
|
+
if missing_pool_fields:
|
|
5933
|
+
raise WalletBackendError(
|
|
5934
|
+
"create existingPool is missing "
|
|
5935
|
+
f"{', '.join(missing_pool_fields)}. Ask the user for the exact existing Uniswap pool; do not infer it from market search data."
|
|
5936
|
+
)
|
|
5937
|
+
elif action in {"increase", "decrease"}:
|
|
5938
|
+
nft_token_id = normalized_request.get("nftTokenId")
|
|
5939
|
+
if not isinstance(nft_token_id, str) or not nft_token_id.strip().isdigit() or int(nft_token_id.strip()) <= 0:
|
|
5940
|
+
raise WalletBackendError(
|
|
5941
|
+
f"{action} requires a positive nftTokenId. Use get_evm_uniswap_positions for V3 or request a verified V4 token id; never infer it."
|
|
5942
|
+
)
|
|
5943
|
+
normalized_request["nftTokenId"] = nft_token_id.strip()
|
|
5944
|
+
else: # claim_fees
|
|
5945
|
+
token_id = normalized_request.get("tokenId", normalized_request.get("nftTokenId"))
|
|
5946
|
+
if not isinstance(token_id, str) or not token_id.strip().isdigit() or int(token_id.strip()) <= 0:
|
|
5947
|
+
raise WalletBackendError(
|
|
5948
|
+
"claim_fees requires the user's positive tokenId (the LP position NFT id). "
|
|
5949
|
+
"Use get_evm_uniswap_positions for V3 or request a verified V4 token id; never infer it."
|
|
5950
|
+
)
|
|
5951
|
+
# The Liquidity API names this field tokenId for fee claims;
|
|
5952
|
+
# accept nftTokenId as the user-facing alias used by other LP actions.
|
|
5953
|
+
normalized_request["tokenId"] = token_id.strip()
|
|
5954
|
+
normalized_request.pop("nftTokenId", None)
|
|
5955
|
+
# The caller must not override values that are derived from the
|
|
5956
|
+
# active wallet/network in the WDK layer.
|
|
5957
|
+
forbidden = {"walletAddress", "chainId", "protocol", "simulateTransaction", "signature", "batchPermitData", "v4BatchPermitData", "v3NftPermitData"}
|
|
5958
|
+
overlap = forbidden.intersection(request)
|
|
5959
|
+
if overlap:
|
|
5960
|
+
raise WalletBackendError(f"request must not set wallet-controlled fields: {', '.join(sorted(overlap))}.")
|
|
5961
|
+
preview_kwargs = {"action": action, "protocol": protocol, "request": normalized_request}
|
|
5962
|
+
if mode == "preview":
|
|
5963
|
+
preview = await active_backend.preview_uniswap_liquidity(**preview_kwargs)
|
|
5964
|
+
return AgentToolResult(tool=tool_name, ok=True, data=self._annotate_sensitive_payload(preview, action_label="Uniswap liquidity", mode="preview"))
|
|
5965
|
+
if mode == "prepare":
|
|
5966
|
+
self._require_prepare_intent(user_intent)
|
|
5967
|
+
preview = await active_backend.preview_uniswap_liquidity(**preview_kwargs)
|
|
5968
|
+
return AgentToolResult(tool=tool_name, ok=True, data=self._annotate_sensitive_payload(self._build_prepare_plan(preview_payload=preview, action_label="Uniswap liquidity"), action_label="Uniswap liquidity", mode="prepare"))
|
|
5969
|
+
if isinstance(approval_token, str) and approval_token.strip():
|
|
5970
|
+
approval_payload = inspect_approval_token(
|
|
5971
|
+
approval_token,
|
|
5972
|
+
tool_name=tool_name,
|
|
5973
|
+
network=str(getattr(active_backend, "network", "unknown")),
|
|
5974
|
+
require_mainnet_confirmation=self._is_mainnet_for_backend(active_backend),
|
|
5975
|
+
)
|
|
5976
|
+
approval_summary = approval_payload.get("binding", {}).get("summary")
|
|
5977
|
+
if not isinstance(approval_summary, dict):
|
|
5978
|
+
raise WalletBackendError("approval_token does not match the requested LP operation. Generate a new approval after prepare.")
|
|
5979
|
+
approval_summary_copy = dict(approval_summary)
|
|
5980
|
+
else:
|
|
5981
|
+
fresh_preview = await active_backend.preview_uniswap_liquidity(**preview_kwargs)
|
|
5982
|
+
approval_summary_copy = self._build_confirmation_summary(action_label="Uniswap liquidity", payload=fresh_preview)
|
|
5983
|
+
expected = {
|
|
5984
|
+
"operation": "Uniswap liquidity",
|
|
5985
|
+
"network": str(getattr(active_backend, "network", "unknown")),
|
|
5986
|
+
"liquidity_action": action,
|
|
5987
|
+
"liquidity_protocol": protocol,
|
|
5988
|
+
}
|
|
5989
|
+
for key, value in expected.items():
|
|
5990
|
+
if approval_summary_copy.get(key) != value:
|
|
5991
|
+
raise WalletBackendError("approval_token does not match the requested LP operation. Generate a new approval after prepare.")
|
|
5992
|
+
# An LP intent deliberately does not bind API-calculated ticks,
|
|
5993
|
+
# price, calldata, or quote amounts: those are regenerated just
|
|
5994
|
+
# before broadcast. It must still be scoped to the selected
|
|
5995
|
+
# assets/pool/position so an approval cannot be reused for a
|
|
5996
|
+
# different liquidity position.
|
|
5997
|
+
requested_scope = self._build_confirmation_summary(
|
|
5998
|
+
action_label="Uniswap liquidity",
|
|
5999
|
+
payload={
|
|
6000
|
+
"asset_type": "evm-uniswap-liquidity",
|
|
6001
|
+
"network": str(getattr(active_backend, "network", "unknown")),
|
|
6002
|
+
"protocol": "uniswap",
|
|
6003
|
+
"liquidity_action": action,
|
|
6004
|
+
"liquidity_protocol": protocol,
|
|
6005
|
+
"request": preview_kwargs["request"],
|
|
6006
|
+
},
|
|
6007
|
+
)
|
|
6008
|
+
for key in ("token0_address", "token1_address", "pool_reference", "position_token_id", "independent_token"):
|
|
6009
|
+
requested_value = requested_scope.get(key)
|
|
6010
|
+
if requested_value is not None and approval_summary_copy.get(key) != requested_value:
|
|
6011
|
+
raise WalletBackendError("approval_token does not match the requested LP assets or position. Generate a new approval after prepare.")
|
|
6012
|
+
self._require_execute_approval(
|
|
6013
|
+
approval_token=approval_token,
|
|
6014
|
+
tool_name=tool_name,
|
|
6015
|
+
summary=approval_summary_copy,
|
|
6016
|
+
action_label="Uniswap liquidity",
|
|
6017
|
+
backend=active_backend,
|
|
6018
|
+
)
|
|
6019
|
+
result = await active_backend.send_uniswap_liquidity(**preview_kwargs)
|
|
6020
|
+
return AgentToolResult(tool=tool_name, ok=True, data=self._annotate_sensitive_payload(result, action_label="Uniswap liquidity", mode="execute"))
|
|
6021
|
+
|
|
5760
6022
|
if tool_name == "issue_wallet_approval":
|
|
5761
6023
|
from agent_wallet.approval import issue_approval_token
|
|
5762
6024
|
|
|
@@ -40,6 +40,8 @@ LONG_RUNNING_POST_PATHS = {
|
|
|
40
40
|
"/v1/evm/swap/send",
|
|
41
41
|
"/v1/evm/uniswap/swap/quote",
|
|
42
42
|
"/v1/evm/uniswap/swap/send",
|
|
43
|
+
"/v1/evm/uniswap/liquidity/quote",
|
|
44
|
+
"/v1/evm/uniswap/liquidity/send",
|
|
43
45
|
"/v1/evm/lifi/quote",
|
|
44
46
|
"/v1/evm/lifi/send",
|
|
45
47
|
"/v1/evm/transfer/send",
|
|
@@ -337,6 +337,25 @@ class AgentWalletBackend(ABC):
|
|
|
337
337
|
) -> dict[str, Any]:
|
|
338
338
|
raise WalletBackendError(f"{self.name} does not support Uniswap pair search.")
|
|
339
339
|
|
|
340
|
+
async def get_uniswap_liquidity_pools(
|
|
341
|
+
self,
|
|
342
|
+
*,
|
|
343
|
+
protocol: str,
|
|
344
|
+
pool_parameters: dict[str, Any] | None = None,
|
|
345
|
+
pool_references: list[dict[str, Any]] | None = None,
|
|
346
|
+
page_size: int = 20,
|
|
347
|
+
current_page: int = 1,
|
|
348
|
+
) -> dict[str, Any]:
|
|
349
|
+
raise WalletBackendError(f"{self.name} does not support Uniswap liquidity pool discovery.")
|
|
350
|
+
|
|
351
|
+
async def get_uniswap_liquidity_positions(
|
|
352
|
+
self,
|
|
353
|
+
*,
|
|
354
|
+
protocol: str = "V3",
|
|
355
|
+
limit: int = 20,
|
|
356
|
+
) -> dict[str, Any]:
|
|
357
|
+
raise WalletBackendError(f"{self.name} does not support Uniswap liquidity position discovery.")
|
|
358
|
+
|
|
340
359
|
async def send_uniswap_swap(
|
|
341
360
|
self,
|
|
342
361
|
*,
|
|
@@ -349,6 +368,24 @@ class AgentWalletBackend(ABC):
|
|
|
349
368
|
) -> dict[str, Any]:
|
|
350
369
|
raise WalletBackendError(f"{self.name} does not support Uniswap swaps.")
|
|
351
370
|
|
|
371
|
+
async def preview_uniswap_liquidity(
|
|
372
|
+
self,
|
|
373
|
+
*,
|
|
374
|
+
action: str,
|
|
375
|
+
protocol: str,
|
|
376
|
+
request: dict[str, Any],
|
|
377
|
+
) -> dict[str, Any]:
|
|
378
|
+
raise WalletBackendError(f"{self.name} does not support Uniswap liquidity previews.")
|
|
379
|
+
|
|
380
|
+
async def send_uniswap_liquidity(
|
|
381
|
+
self,
|
|
382
|
+
*,
|
|
383
|
+
action: str,
|
|
384
|
+
protocol: str,
|
|
385
|
+
request: dict[str, Any],
|
|
386
|
+
) -> dict[str, Any]:
|
|
387
|
+
raise WalletBackendError(f"{self.name} does not support Uniswap liquidity operations.")
|
|
388
|
+
|
|
352
389
|
async def preview_evm_native_transfer(
|
|
353
390
|
self,
|
|
354
391
|
*,
|