> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sei.io/llms.txt
> Use this file to discover all available pages before exploring further.

# CosmWasm Precompile

> Learn how to interact with Sei's CosmWasm precompile through ethers.js, enabling execution, batch operations, and querying of pre-existing CosmWasm contracts directly from your EVM smart contracts.

**Address:** `0x0000000000000000000000000000000000001002`

<Danger>
  **Deprecation Notice — Prop 115 & Prop 116**

  Per [governance Proposal 115](https://www.mintscan.io/sei/proposals/115), CosmWasm code uploads (`MsgStoreCode`) and contract instantiations (`MsgInstantiateContract`) are disabled chain-wide. The `instantiate()` function on this precompile **will revert** for all callers. Only `execute()`, `execute_batch()`, and `query()` against pre-existing CosmWasm contracts remain functional, and all CosmWasm functionality is deprecated in favor of EVM-only per [SIP-3](https://github.com/sei-protocol/sips/blob/main/sips/sip-3.md).

  In addition, [Proposal 116](https://www.mintscan.io/sei/proposals/116) disables inbound IBC transfers — IBC assets bridged from Cosmos chains can no longer arrive on Sei after this passes and is activated. See the [SIP-03 Migration Guide](/learn/sip-03-migration) for affected assets and migration routes.

  For new smart contract development, use the EVM directly. See [Deploy a Smart Contract](/evm/evm-general).
</Danger>

The Sei CosmWasm precompile allows EVM applications to interact directly with **pre-existing** CosmWasm contracts through standard smart contract calls. This enables execution, batch operations, and querying of CosmWasm contracts directly from your dApps without needing separate Cosmos SDK integration.

<Info> **What is a precompile?** A precompile is a special smart contract deployed at a fixed address by the Sei protocol itself, that exposes custom native chain logic to EVM-based applications. It acts like a regular contract from the EVM's perspective, but executes privileged, low-level logic efficiently. </Info>

## How Does the CosmWasm Precompile Work?

The CosmWasm precompile at address `0x0000000000000000000000000000000000001002` exposes functions like `execute()`, `execute_batch()`, and `query()`.

* **Direct Integration:** EVM contracts and dApps can call CosmWasm functions like any other smart contract method.
* **Native Execution:** Operations are executed at the Cosmos SDK level for maximum efficiency and security.
* **Seamless Bridge:** No need for separate wallet integrations or complex cross-chain interactions.

## What You'll Learn in This Guide

By the end of this guide, you'll be able to:

* **Execute Contract Functions** - Call CosmWasm contract methods and handle message formatting
* **Batch Operations** - Execute multiple contract calls efficiently in a single transaction
* **Query Contract State** - Read CosmWasm contract data without gas costs
* **Handle Cross-Runtime Data** - Master message encoding/decoding between EVM and CosmWasm formats

## Functions

The CosmWasm precompile exposes the following functions:

### Transaction Functions

<Warning>The `instantiate()` function has been disabled by [Prop 115](https://www.mintscan.io/sei/proposals/115) and will revert. It is omitted from this reference. The ABI in `@sei-js/precompiles` may still expose it for backwards compatibility, but calling it on-chain will fail.</Warning>

```solidity theme={"dark"}
/// Executes some message on a CosmWasm contract.
/// @param contractAddress The Sei address of the contract to execute.
/// @param msg The msg to send for execution. The format is specified by the contract code.
/// @param coins Any non-sei denominations that the contract requires for execution.
/// @return response The execution response from the CosmWasm contract.
function execute(
    string memory contractAddress,
    bytes memory msg,
    bytes memory coins
) payable external returns (bytes memory response);

struct ExecuteMsg {
    string contractAddress;
    bytes msg;
    bytes coins;
}

/// Executes collection of messages on CosmWasm contracts.
/// @param executeMsgs Array of execution messages to process.
/// @return responses The execution responses collection from the CosmWasm contracts.
function execute_batch(
    ExecuteMsg[] memory executeMsgs
) payable external returns (bytes[] memory responses);
```

### Query Functions

```solidity theme={"dark"}
/// Queries a CosmWasm contract.
/// @param contractAddress The Sei address of the contract to query.
/// @param req The query request object. The format is specified by the contract code.
/// @return response The response from the CosmWasm contract.
function query(
    string memory contractAddress,
    bytes memory req
) external view returns (bytes memory response);
```

## Using the Precompile

### Setup

#### Prerequisites

Before getting started, ensure you have:

* **Node.js** (v18 or higher)
* **npm** or **yarn** package manager
* **EVM-compatible wallet**
* **SEI tokens** for gas and contract operations

#### Install Dependencies

Install the required packages for interacting with Sei precompiles:

```bash theme={"dark"}
# Install ethers.js for smart contract interactions
npm install ethers

# Install Sei EVM bindings for precompile addresses and ABIs
npm install @sei-js/precompiles@2.1.2
```

#### Import Precompile Components

```typescript theme={"dark"}
// Import CosmWasm precompile address and ABI
// View the entire ABI here: https://github.com/sei-protocol/sei-chain/tree/main/precompiles/wasmd
import { WASM_PRECOMPILE_ABI, WASM_PRECOMPILE_ADDRESS } from '@sei-js/precompiles';
import { ethers } from 'ethers';
```

<Info> **Precompile Address:** The CosmWasm precompile is deployed at `0x0000000000000000000000000000000000001002` </Info>

### Contract Initialization

Set up your provider, signer, and contract instance:

```typescript theme={"dark"}
// Using EVM-compatible wallet as the signer and provider
const provider = new ethers.BrowserProvider(window.ethereum);
await provider.send('eth_requestAccounts', []);
const signer = await provider.getSigner();

// Create a contract instance for the CosmWasm precompile
const cosmwasm = new ethers.Contract(WASM_PRECOMPILE_ADDRESS, WASM_PRECOMPILE_ABI, signer);
```

## Critical: Understanding Message Formats

One of the most important concepts to understand when working with the Sei CosmWasm precompile:

### CosmWasm Message Structure

The CosmWasm precompile requires **JSON-encoded messages** that conform to each contract's specific schema:

| Function          | Input/Output          | Format Type | Example                                     |
| ----------------- | --------------------- | ----------- | ------------------------------------------- |
| `execute()`       | msg parameter (input) | JSON bytes  | `ethers.toUtf8Bytes(jsonString)`            |
| `query()`         | req parameter (input) | JSON bytes  | `ethers.toUtf8Bytes(jsonString)`            |
| **All functions** | response (output)     | JSON bytes  | `JSON.parse(ethers.toUtf8String(response))` |

### How Message Encoding Works

**All CosmWasm functions require JSON-encoded byte arrays:**

* `execute()` - accepts execution message as JSON bytes
* `query()` - accepts query message as JSON bytes

**Native Token Handling:**

* Use `msg.value` for SEI amounts
* Use `coins` parameter for other denominations (encoded as JSON bytes)

### Best Practice: Message Encoding Helpers

When working with CosmWasm messages, use proper JSON encoding:

```typescript theme={"dark"}
// Helper functions for message encoding
class CosmWasmMessageEncoder {
  // Encode execute message
  static encodeExecuteMsg(msg: object): Uint8Array {
    return ethers.toUtf8Bytes(JSON.stringify(msg));
  }

  // Encode query message
  static encodeQueryMsg(msg: object): Uint8Array {
    return ethers.toUtf8Bytes(JSON.stringify(msg));
  }

  // Encode coins for non-SEI denominations
  static encodeCoins(coins: Array<{ denom: string; amount: string }>): Uint8Array {
    if (coins.length === 0) return new Uint8Array();
    return ethers.toUtf8Bytes(JSON.stringify(coins));
  }

  // Decode response bytes to JSON
  static decodeResponse(responseBytes: Uint8Array): any {
    const jsonString = ethers.toUtf8String(responseBytes);
    return JSON.parse(jsonString);
  }
}

// Usage examples
const executeMsg = CosmWasmMessageEncoder.encodeExecuteMsg({
  transfer: {
    recipient: 'sei1...',
    amount: '1000000'
  }
});

const queryMsg = CosmWasmMessageEncoder.encodeQueryMsg({
  balance: { address: 'sei1...' }
});
```

## Message Format Helpers

Use these helper functions to handle CosmWasm message formatting:

```typescript theme={"dark"}
// Helper functions for CosmWasm message handling
class CosmWasmHelper {
  // Create execute message bytes
  static createExecuteMsg(msgObject: any): Uint8Array {
    return ethers.toUtf8Bytes(JSON.stringify(msgObject));
  }

  // Create query message bytes
  static createQueryMsg(msgObject: any): Uint8Array {
    return ethers.toUtf8Bytes(JSON.stringify(msgObject));
  }

  // Create coins array for non-SEI denominations
  static createCoins(coins: Array<{ denom: string; amount: string }>): Uint8Array {
    if (!coins || coins.length === 0) {
      return ethers.toUtf8Bytes('[]');
    }
    return ethers.toUtf8Bytes(JSON.stringify(coins));
  }

  // Parse response from CosmWasm contract
  static parseResponse(responseBytes: string | Uint8Array): any {
    try {
      const jsonString = typeof responseBytes === 'string' ? responseBytes : ethers.toUtf8String(responseBytes);
      return JSON.parse(jsonString);
    } catch (error) {
      console.error('Failed to parse CosmWasm response:', error);
      return null;
    }
  }
}

// Usage examples
const executeMsg = CosmWasmHelper.createExecuteMsg({
  mint: {
    recipient: 'sei1recipient...',
    amount: '1000000'
  }
});

const coins = CosmWasmHelper.createCoins([{ denom: 'uusdc', amount: '1000000' }]);
```

## Step-by-Step Guide: Using the CosmWasm Precompile

### Execute a CosmWasm Contract

<Tabs>
  <Tab title="JavaScript">
    ```typescript theme={"dark"}
    // Execute a transfer on a CW20 token contract
    const contractAddress = 'sei1contract...'; // Your CosmWasm contract address

    // Create execute message for CW20 transfer
    const executeMsg = CosmWasmHelper.createExecuteMsg({
      transfer: {
        recipient: 'sei1recipient...',
        amount: '1000000' // 1 token with 6 decimals
      }
    });

    // No additional coins needed for this execution
    const coins = CosmWasmHelper.createCoins([]);

    const tx = await cosmwasm.execute(contractAddress, executeMsg, coins);

    const receipt = await tx.wait();
    console.log('Transfer executed:', receipt);

    // Parse the response if needed
    const response = CosmWasmHelper.parseResponse(receipt.logs[0].data);
    console.log('Execution response:', response);
    ```
  </Tab>

  <Tab title="Solidity">
    ```solidity theme={"dark"}
    contract CosmWasmExecutor {
        ICosmWasm constant COSMWASM = ICosmWasm(0x0000000000000000000000000000000000001002);

        event ContractExecuted(string contractAddress, bytes response);

        function executeContract(
            string memory contractAddress,
            bytes memory msg,
            bytes memory coins
        ) external payable {
            bytes memory response = COSMWASM.execute{value: msg.value}(
                contractAddress,
                msg,
                coins
            );

            emit ContractExecuted(contractAddress, response);
        }
    }
    ```
  </Tab>
</Tabs>

### Execute Batch Operations

<Tabs>
  <Tab title="JavaScript">
    ```typescript theme={"dark"}
    // Execute multiple operations in a single transaction
    const contract1 = 'sei1contract1...';
    const contract2 = 'sei1contract2...';

    // Create multiple execute messages
    const executeMsg1 = CosmWasmHelper.createExecuteMsg({
      transfer: {
        recipient: 'sei1recipient1...',
        amount: '500000'
      }
    });

    const executeMsg2 = CosmWasmHelper.createExecuteMsg({
      mint: {
        recipient: 'sei1recipient2...',
        amount: '1000000'
      }
    });

    // Create batch execution array
    const executeMsgs = [
      {
        contractAddress: contract1,
        msg: executeMsg1,
        coins: CosmWasmHelper.createCoins([])
      },
      {
        contractAddress: contract2,
        msg: executeMsg2,
        coins: CosmWasmHelper.createCoins([])
      }
    ];

    const tx = await cosmwasm.execute_batch(executeMsgs);
    const receipt = await tx.wait();

    console.log('Batch execution completed:', receipt);
    ```
  </Tab>

  <Tab title="Solidity">
    ```solidity theme={"dark"}
    contract BatchExecutor {
        ICosmWasm constant COSMWASM = ICosmWasm(0x0000000000000000000000000000000000001002);

        function executeBatch(
            ICosmWasm.ExecuteMsg[] memory executeMsgs
        ) external payable {
            bytes[] memory responses = COSMWASM.execute_batch{value: msg.value}(executeMsgs);

            // Process responses as needed
            for (uint i = 0; i < responses.length; i++) {
                // Handle each response
                emit BatchResponseReceived(i, responses[i]);
            }
        }

        event BatchResponseReceived(uint index, bytes response);
    }
    ```
  </Tab>
</Tabs>

### Query a CosmWasm Contract

<Tabs>
  <Tab title="JavaScript">
    ```typescript theme={"dark"}
    // Query balance of a CW20 token
    const contractAddress = 'sei1contract...';
    const userAddress = 'sei1user...';

    // Create query message
    const queryMsg = CosmWasmHelper.createQueryMsg({
      balance: { address: userAddress }
    });

    try {
      const responseBytes = await cosmwasm.query(contractAddress, queryMsg);
      const response = CosmWasmHelper.parseResponse(responseBytes);

      console.log('User balance:', response.balance);

      // Query token info
      const tokenInfoMsg = CosmWasmHelper.createQueryMsg({ token_info: {} });
      const tokenInfoBytes = await cosmwasm.query(contractAddress, tokenInfoMsg);
      const tokenInfo = CosmWasmHelper.parseResponse(tokenInfoBytes);

      console.log('Token info:', {
        name: tokenInfo.name,
        symbol: tokenInfo.symbol,
        decimals: tokenInfo.decimals,
        total_supply: tokenInfo.total_supply
      });
    } catch (error) {
      console.error('Query failed:', error);
    }
    ```
  </Tab>

  <Tab title="Solidity">
    ```solidity theme={"dark"}
    contract CosmWasmQuery {
        ICosmWasm constant COSMWASM = ICosmWasm(0x0000000000000000000000000000000000001002);

        function queryContract(
            string memory contractAddress,
            bytes memory queryMsg
        ) external view returns (bytes memory) {
            return COSMWASM.query(contractAddress, queryMsg);
        }

        // Helper to query and decode in one call (requires additional parsing logic)
        function queryBalance(
            string memory contractAddress,
            string memory userAddress
        ) external view returns (bytes memory) {
            // This would require JSON parsing in Solidity, which is complex
            // Better to handle parsing off-chain
            bytes memory queryMsg = abi.encode('{"balance":{"address":"', userAddress, '"}}');
            return COSMWASM.query(contractAddress, queryMsg);
        }
    }
    ```
  </Tab>
</Tabs>

<Warning> **Query Limitations:** CosmWasm queries are read-only operations and don't consume gas, but parsing JSON responses in Solidity is complex. Consider handling response parsing off-chain. </Warning>

## Advanced Usage Examples

### Cross-Runtime DeFi Integration

```typescript theme={"dark"}
async function crossRuntimeDeFiOperation(cosmwasmDexContract: string, evmTokenContract: string, amount: string) {
  try {
    // 1. Execute swap on CosmWasm DEX
    const swapMsg = CosmWasmHelper.createExecuteMsg({
      swap: {
        offer_asset: {
          info: { native_token: { denom: 'usei' } },
          amount: amount
        },
        belief_price: '1.0'
      }
    });

    const swapTx = await cosmwasm.execute(cosmwasmDexContract, swapMsg, CosmWasmHelper.createCoins([]), { value: ethers.parseEther(amount) });

    await swapTx.wait();
    console.log('CosmWasm swap completed');

    // 2. Query swap result
    const balanceMsg = CosmWasmHelper.createQueryMsg({
      balance: { address: await signer.getAddress() }
    });

    const balanceResponse = await cosmwasm.query(cosmwasmDexContract, balanceMsg);
    const balance = CosmWasmHelper.parseResponse(balanceResponse);

    console.log('New balance after swap:', balance);

    return balance;
  } catch (error) {
    console.error('Cross-runtime operation failed:', error);
    throw error;
  }
}
```

### Complete Integration Example

<Tabs>
  <Tab title="JavaScript">
    ```typescript theme={"dark"}
    async function cosmwasmExample() {
      // Setup
      const provider = new ethers.BrowserProvider(window.ethereum);
      await provider.send('eth_requestAccounts', []);
      const signer = await provider.getSigner();
      const cosmwasm = new ethers.Contract(WASM_PRECOMPILE_ADDRESS, WASM_PRECOMPILE_ABI, signer);

      const userAddress = await signer.getAddress();

      // Replace with the address of an existing CosmWasm contract you want to interact with.
      const contractAddress = 'sei1contract...';

      try {
        // 1. Execute mint operation against an existing contract
        console.log('=== Minting Tokens ===');
        const mintMsg = CosmWasmHelper.createExecuteMsg({
          mint: {
            recipient: 'sei1recipient...',
            amount: '1000000000' // 1000 tokens
          }
        });

        const mintTx = await cosmwasm.execute(contractAddress, mintMsg, CosmWasmHelper.createCoins([]));
        await mintTx.wait();
        console.log('Tokens minted successfully');

        // 2. Query token information
        console.log('=== Querying Token Info ===');
        const tokenInfoMsg = CosmWasmHelper.createQueryMsg({ token_info: {} });
        const tokenInfoBytes = await cosmwasm.query(contractAddress, tokenInfoMsg);
        const tokenInfo = CosmWasmHelper.parseResponse(tokenInfoBytes);

        console.log('Token Info:', {
          name: tokenInfo.name,
          symbol: tokenInfo.symbol,
          decimals: tokenInfo.decimals,
          total_supply: tokenInfo.total_supply
        });

        // 3. Query user balance
        const balanceMsg = CosmWasmHelper.createQueryMsg({
          balance: { address: 'sei1recipient...' }
        });
        const balanceBytes = await cosmwasm.query(contractAddress, balanceMsg);
        const balance = CosmWasmHelper.parseResponse(balanceBytes);

        console.log('User balance:', balance.balance);

        // 4. Execute batch transfer
        console.log('=== Batch Transfer ===');
        const batchMsgs = [
          {
            contractAddress: contractAddress,
            msg: CosmWasmHelper.createExecuteMsg({
              transfer: {
                recipient: 'sei1addr1...',
                amount: '100000000' // 100 tokens
              }
            }),
            coins: CosmWasmHelper.createCoins([])
          },
          {
            contractAddress: contractAddress,
            msg: CosmWasmHelper.createExecuteMsg({
              transfer: {
                recipient: 'sei1addr2...',
                amount: '200000000' // 200 tokens
              }
            }),
            coins: CosmWasmHelper.createCoins([])
          }
        ];

        const batchTx = await cosmwasm.execute_batch(batchMsgs);
        await batchTx.wait();
        console.log('Batch transfer completed');
      } catch (error) {
        console.error('CosmWasm operation failed:', error);
      }
    }
    ```
  </Tab>

  <Tab title="Solidity">
    **Contract Example**

    ```solidity theme={"dark"}
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;

    interface ICosmWasmPrecompile {
        struct ExecuteMsg {
            string contractAddress;
            bytes msg;
            bytes coins;
        }

        function execute(
            string memory contractAddress,
            bytes memory msg,
            bytes memory coins
        ) payable external returns (bytes memory response);

        function execute_batch(
            ExecuteMsg[] memory executeMsgs
        ) payable external returns (bytes[] memory responses);

        function query(
            string memory contractAddress,
            bytes memory req
        ) external view returns (bytes memory response);
    }

    contract CosmWasmBridge {
        ICosmWasmPrecompile constant COSMWASM = ICosmWasmPrecompile(0x0000000000000000000000000000000000001002);

        event ContractExecuted(string contractAddress, bytes response);
        event BatchExecuted(uint256 msgCount);
        event QueryExecuted(string contractAddress, bytes response);

        // Execute a message on a CosmWasm contract
        function executeContract(
            string memory contractAddress,
            bytes memory executeMsg,
            bytes memory coins
        ) external payable returns (bytes memory) {
            bytes memory response = COSMWASM.execute{value: msg.value}(
                contractAddress,
                executeMsg,
                coins
            );

            emit ContractExecuted(contractAddress, response);
            return response;
        }

        // Execute multiple messages in batch
        function executeBatch(
            ICosmWasmPrecompile.ExecuteMsg[] memory executeMsgs
        ) external payable returns (bytes[] memory) {
            bytes[] memory responses = COSMWASM.execute_batch{value: msg.value}(executeMsgs);

            emit BatchExecuted(executeMsgs.length);
            return responses;
        }

        // Query a CosmWasm contract
        function queryContract(
            string memory contractAddress,
            bytes memory queryMsg
        ) external view returns (bytes memory) {
            bytes memory response = COSMWASM.query(contractAddress, queryMsg);

            // Note: Cannot emit events in view functions
            return response;
        }

        // Helper function to create execute message struct
        function createExecuteMsg(
            string memory contractAddress,
            bytes memory msg,
            bytes memory coins
        ) public pure returns (ICosmWasmPrecompile.ExecuteMsg memory) {
            return ICosmWasmPrecompile.ExecuteMsg({
                contractAddress: contractAddress,
                msg: msg,
                coins: coins
            });
        }
    }
    ```

    <Info> **Note:** This contract acts as a bridge between EVM and existing CosmWasm contracts. Message encoding/decoding should be handled client-side for complex operations. </Info>

    **Client Integration Example**

    ```javascript theme={"dark"}
    import { network } from 'hardhat';

    // Hardhat 3 exposes ethers through a network connection rather than a global import
    const { ethers } = await network.create();

    async function main() {
      const [deployer] = await ethers.getSigners();
      console.log('Deploying contracts with the account:', deployer.address);

      const CosmWasmBridge = await ethers.getContractFactory('CosmWasmBridge');
      console.log('Deploying CosmWasmBridge...');
      const bridge = await CosmWasmBridge.deploy();

      await bridge.waitForDeployment();
      console.log('CosmWasmBridge deployed to:', await bridge.getAddress());

      // Address of an existing CosmWasm contract you want to interact with
      const contractAddress = 'sei1contract...';

      // Encode an execute message (e.g., a CW20 transfer)
      const executeMsg = ethers.toUtf8Bytes(
        JSON.stringify({
          transfer: {
            recipient: 'sei1recipient...',
            amount: '1000000'
          }
        })
      );

      const coins = ethers.toUtf8Bytes('[]');

      const tx = await bridge.executeContract(contractAddress, executeMsg, coins);
      const receipt = await tx.wait();

      console.log('Execute transaction hash:', tx.hash);

      const event = receipt.logs.find((log) => log.topics[0] === ethers.id('ContractExecuted(string,bytes)'));

      if (event) {
        console.log('CosmWasm execute call confirmed');
      }
    }

    main().catch((error) => {
      console.error(error);
      process.exitCode = 1;
    });
    ```
  </Tab>
</Tabs>

## Troubleshooting

### Common Issues and Solutions

#### Message Encoding Issues

```typescript theme={"dark"}
// Ensure proper JSON encoding for messages
const msg = {
  transfer: {
    recipient: 'sei1...',
    amount: '1000000' // Use strings for large numbers
  }
};

// Correct encoding
const encodedMsg = ethers.toUtf8Bytes(JSON.stringify(msg));

// Incorrect - will cause parsing errors
const incorrectMsg = ethers.toUtf8Bytes('invalid json');
```

### Error Code Reference

| Error                  | Cause                           | Solution                            |
| ---------------------- | ------------------------------- | ----------------------------------- |
| `invalid json`         | Malformed JSON message          | Validate JSON before encoding       |
| `contract not found`   | Invalid contract address        | Verify contract address format      |
| `insufficient funds`   | Not enough tokens for operation | Check balance and reduce amount     |
| `execution failed`     | Contract execution error        | Check contract state and parameters |
| `unauthorized`         | Insufficient permissions        | Check admin/owner permissions       |
| `query parsing failed` | Invalid query message format    | Match contract's query schema       |

## Important Notes

<Info> Remember the key rule: All CosmWasm messages must be properly JSON-encoded as bytes, and contract schemas vary by implementation! </Info>

### Message Format Requirements

* **JSON Encoding:** All messages must be valid JSON encoded as UTF-8 bytes, invalid JSON will cause transaction failures
* **Schema Compliance:** Messages must match the contract's expected format
* **Type Safety:** Use proper data types as expected by the contract

### Contract Address Format

* Use valid Sei contract addresses with `sei1...` prefix
* These are Cosmos-format addresses, not EVM addresses
* **Contract Existence:** Verify contracts exist before calling

### Cross-Runtime Considerations

* **State Isolation:** CosmWasm and EVM contracts have separate state
* **Gas Estimation:** CosmWasm operations may require different gas calculations
* **Error Handling:** Failed CosmWasm operations revert the entire EVM transaction
* **Native Token Handling:** Use `msg.value` for SEI, `coins` for other denominations
* **Batch Limitations:** Large batches may hit gas limits

### Best Practices

* Always validate JSON messages before sending
* Handle response parsing carefully, especially for complex data structures
* Use batch operations for multiple related calls to save gas
* Query contracts before executing to verify state when possible

<Info>View the CosmWasm precompile source code and the contract ABI [here](https://github.com/sei-protocol/sei-chain/tree/main/precompiles/wasmd).</Info>
