Skip to main content
Glama

add_liquidity

Add liquidity to trading pools on Paloma DEX across multiple EVM chains by specifying token amounts and addresses to receive transaction details.

Instructions

Add liquidity to a trading pool using the Trader contract.

Args:
    chain_id: Chain ID (1, 10, 56, 100, 137, 8453, 42161)
    token0_address: Address of first token
    token1_address: Address of second token
    token0_amount: Amount of first token in wei
    token1_amount: Amount of second token in wei

Returns:
    JSON string with liquidity addition transaction details.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
chain_idYes
token0_addressYes
token1_addressYes
token0_amountYes
token1_amountYes

Implementation Reference

  • The MCP tool handler for 'add_liquidity'. It validates inputs, builds and sends a transaction to the Trader contract's add_liquidity function on the specified EVM chain, and returns transaction details including explorer link.
    @mcp.tool()
    async def add_liquidity(ctx: Context, chain_id: str, token0_address: str, token1_address: str, token0_amount: str, token1_amount: str) -> str:
        """Add liquidity to a trading pool using the Trader contract.
        
        Args:
            chain_id: Chain ID (1, 10, 56, 100, 137, 8453, 42161)
            token0_address: Address of first token
            token1_address: Address of second token
            token0_amount: Amount of first token in wei
            token1_amount: Amount of second token in wei
        
        Returns:
            JSON string with liquidity addition transaction details.
        """
        try:
            paloma_ctx = ctx.request_context.lifespan_context
            
            if chain_id not in CHAIN_CONFIGS:
                return f"Error: Unsupported chain ID {chain_id}"
            
            config = CHAIN_CONFIGS[chain_id]
            
            if chain_id not in paloma_ctx.web3_clients:
                return f"Error: Web3 client not available for {config.name}"
            
            trader_address = TRADER_ADDRESSES.get(chain_id)
            if not trader_address:
                return f"Error: Trader contract not configured for {config.name}"
            
            # Validate addresses and amounts
            if not Web3.is_address(token0_address):
                return f"Error: Invalid token0 address: {token0_address}"
            
            if not Web3.is_address(token1_address):
                return f"Error: Invalid token1 address: {token1_address}"
            
            try:
                amount0_int = int(token0_amount)
                amount1_int = int(token1_amount)
                if amount0_int <= 0 or amount1_int <= 0:
                    raise ValueError("Amounts must be positive")
            except ValueError:
                return f"Error: Invalid amounts: {token0_amount}, {token1_amount}"
            
            web3 = paloma_ctx.web3_clients[chain_id]
            trader_contract = web3.eth.contract(address=trader_address, abi=TRADER_ABI)
            
            # Get gas fee from contract
            try:
                gas_fee = trader_contract.functions.gas_fee().call()
            except Exception as e:
                logger.warning(f"Failed to get gas fee from contract: {e}, using 0")
                gas_fee = 0
            
            # Build transaction
            add_liquidity_tx_data = trader_contract.functions.add_liquidity(
                token0_address,
                token1_address,
                amount0_int,
                amount1_int
            ).build_transaction({
                'from': paloma_ctx.address,
                'value': gas_fee,
                'gasPrice': web3.to_wei(config.gas_price_gwei, 'gwei'),
                'nonce': web3.eth.get_transaction_count(paloma_ctx.address)
            })
            
            # Estimate gas with buffer
            try:
                estimated_gas = web3.eth.estimate_gas(add_liquidity_tx_data)
                buffered_gas = estimated_gas + (estimated_gas // GAS_MULTIPLIER)
                add_liquidity_tx_data['gas'] = buffered_gas
            except Exception as e:
                logger.warning(f"Gas estimation failed: {e}, using default")
                add_liquidity_tx_data['gas'] = 400000
            
            # Sign and send transaction
            signed_tx = paloma_ctx.account.sign_transaction(add_liquidity_tx_data)
            tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
            
            # Wait for confirmation
            receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
            
            # Get token symbols for display
            try:
                token0_contract = web3.eth.contract(address=token0_address, abi=ERC20_ABI)
                token1_contract = web3.eth.contract(address=token1_address, abi=ERC20_ABI)
                token0_symbol = token0_contract.functions.symbol().call()
                token1_symbol = token1_contract.functions.symbol().call()
                token0_decimals = token0_contract.functions.decimals().call()
                token1_decimals = token1_contract.functions.decimals().call()
            except:
                token0_symbol = "Unknown"
                token1_symbol = "Unknown"
                token0_decimals = 18
                token1_decimals = 18
            
            amount0_display = float(amount0_int) / (10 ** token0_decimals)
            amount1_display = float(amount1_int) / (10 ** token1_decimals)
            
            result = {
                "chain": config.name,
                "chain_id": config.chain_id,
                "trader_contract": trader_address,
                "token0": {
                    "address": token0_address,
                    "symbol": token0_symbol,
                    "amount_wei": token0_amount,
                    "amount_display": str(amount0_display)
                },
                "token1": {
                    "address": token1_address,
                    "symbol": token1_symbol,
                    "amount_wei": token1_amount,
                    "amount_display": str(amount1_display)
                },
                "transaction": {
                    "hash": tx_hash.hex(),
                    "status": "success" if receipt.status == 1 else "failed",
                    "gas_used": receipt.gasUsed,
                    "gas_fee_paid": str(gas_fee),
                    "block_number": receipt.blockNumber
                },
                "explorer_url": f"{config.explorer_url}/tx/{tx_hash.hex()}"
            }
            
            return json.dumps(result, indent=2)
            
        except Exception as e:
            logger.error(f"Error adding liquidity: {e}")
            return f"Error adding liquidity: {str(e)}"
  • ABI schema definition for the Trader contract's add_liquidity function, specifying the input parameters (token0, token1, amount0, amount1) that match the tool's parameters.
        "name": "add_liquidity",
        "type": "function",
        "inputs": [
            {"name": "token0", "type": "address"},
            {"name": "token1", "type": "address"},
            {"name": "amount0", "type": "uint256"},
            {"name": "amount1", "type": "uint256"}
        ],
        "outputs": [],
        "stateMutability": "payable"
    },
  • padex.py:1896-1896 (registration)
    FastMCP decorator that registers the add_liquidity function as an MCP tool.
    @mcp.tool()
  • TRADER_ABI defines the contract interface used by the add_liquidity handler, including the ABI for add_liquidity and supporting functions like gas_fee.
    TRADER_ABI = [
        {
            "name": "purchase",
            "type": "function",
            "inputs": [
                {"name": "from_token", "type": "address"},
                {"name": "to_token", "type": "address"},
                {"name": "amount", "type": "uint256"}
            ],
            "outputs": [],
            "stateMutability": "payable"
        },
        {
            "name": "add_liquidity",
            "type": "function",
            "inputs": [
                {"name": "token0", "type": "address"},
                {"name": "token1", "type": "address"},
                {"name": "amount0", "type": "uint256"},
                {"name": "amount1", "type": "uint256"}
            ],
            "outputs": [],
            "stateMutability": "payable"
        },
        {
            "name": "remove_liquidity",
            "type": "function",
            "inputs": [
                {"name": "token0", "type": "address"},
                {"name": "token1", "type": "address"},
                {"name": "amount", "type": "uint256"}
            ],
            "outputs": [],
            "stateMutability": "payable"
        },
        {
            "name": "gas_fee",
            "type": "function",
            "inputs": [],
            "outputs": [{"name": "", "type": "uint256"}],
            "stateMutability": "view"
        }
    ]
  • Chain-specific Trader contract addresses used by the add_liquidity handler to locate the contract for liquidity addition.
    TRADER_ADDRESSES = {
        ChainID.ETHEREUM_MAIN: "0x7230EC05eD8c38D5be6f58Ae41e30D1ED6cfDAf1",
        ChainID.ARBITRUM_MAIN: "0x36B8763b3b71685F21512511bB433f4A0f50213E", 
        ChainID.BASE_MAIN: "0xd58Dfd5b39fCe87dD9C434e95428DdB289934179",
        ChainID.BSC_MAIN: "0x8ee509a97279029071AB66Cb0391e8Dc67a137f9",
        ChainID.GNOSIS_MAIN: "0xd58Dfd5b39fCe87dD9C434e95428DdB289934179",
        ChainID.OPTIMISM_MAIN: "0xB6d4AAFfBbceB5e363352179E294326C91d6c127",
        ChainID.POLYGON_MAIN: "0xB6d4AAFfBbceB5e363352179E294326C91d6c127"
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It states the action is 'add liquidity' which implies a write/mutation operation, but doesn't disclose critical behavioral traits: whether this requires token approvals first, gas costs, transaction finality, slippage considerations, or what happens if pool doesn't exist. The return format is mentioned but without details on error cases or transaction status.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured with a clear purpose statement followed by well-organized parameter documentation. Every sentence earns its place: the first establishes context, the Args section documents all inputs, and the Returns section sets expectations. No redundant information or unnecessary elaboration.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter mutation tool with no annotations and no output schema, the description provides adequate but incomplete coverage. It documents all parameters well and mentions the return format, but lacks critical behavioral context about prerequisites, costs, and error conditions. The agent would need additional knowledge about DeFi protocols to use this tool safely.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate - and it does well by documenting all 5 parameters with clear explanations. It adds crucial semantic context beyond schema titles: chain IDs are enumerated, token amounts are in wei, and the token address parameters are clearly identified. The only minor gap is lack of format details for addresses (e.g., checksummed, 0x-prefixed).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Add liquidity') and resource ('to a trading pool using the Trader contract'), which is specific and unambiguous. It distinguishes from sibling tools like 'remove_liquidity' by specifying the direction of liquidity movement. However, it doesn't explicitly differentiate from other trading-related tools like 'execute_token_swap' beyond the verb 'add'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (like token approval via 'approve_token_spending'), when liquidity addition is appropriate versus other trading actions, or any constraints on pool selection. The agent must infer usage context from the tool name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/VolumeFi/mcpPADEX'

If you have feedback or need assistance with the MCP directory API, please join our Discord server