Documentation Index
Fetch the complete documentation index at: https://seilabs.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Address: 0x0000000000000000000000000000000000001002
Deprecation Notice — Prop 115Per governance Proposal 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.For new smart contract development, use the EVM directly. See Deploy a Smart Contract.
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.
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.
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
The
instantiate() function has been disabled by
Prop 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.
/// 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
/// 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 fees and contract operations
Install Dependencies
Install the required packages for interacting with Sei precompiles:
# 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
// 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';
Precompile Address: The CosmWasm precompile is deployed at 0x0000000000000000000000000000000000001002
Contract Initialization
Set up your provider, signer, and contract instance:
// 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);
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:
// 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...' }
});
Use these helper functions to handle CosmWasm message formatting:
// 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
// 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);
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);
}
}
Execute Batch Operations
// 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);
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);
}
Query a CosmWasm Contract
// 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);
}
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);
}
}
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.
Advanced Usage Examples
Cross-Runtime DeFi Integration
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
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);
}
}
Contract Example// 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
});
}
}
Note: This contract acts as a bridge between EVM and existing CosmWasm contracts. Message encoding/decoding should be handled client-side for complex operations.
Client Integration Exampleconst abi = require('./artifacts/contracts/CosmWasmBridge.sol/CosmWasmBridge.json');
const { ethers } = require('hardhat');
const dotenv = require('dotenv');
dotenv.config();
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;
});
Troubleshooting
Common Issues and Solutions
Message Encoding Issues
// 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
Remember the key rule: All CosmWasm messages must be properly JSON-encoded as bytes, and contract schemas vary by implementation!
- 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
- 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
View the CosmWasm precompile source code and the contract ABI
here.