diff --git a/.github/styles/Sei/Headings.yml b/.github/styles/Sei/Headings.yml index fbba533..5156e6c 100644 --- a/.github/styles/Sei/Headings.yml +++ b/.github/styles/Sei/Headings.yml @@ -31,7 +31,6 @@ exceptions: - CLI - SDK - NFT - - IBC - VRF - JSON - RocksDB diff --git a/ai/sei-skill/prompts.mdx b/ai/sei-skill/prompts.mdx index a60790d..89969cc 100644 --- a/ai/sei-skill/prompts.mdx +++ b/ai/sei-skill/prompts.mdx @@ -22,7 +22,7 @@ How do I call the Staking precompile from Solidity to delegate SEI? Why does SSTORE cost more on Sei than on Ethereum, and how should I budget gas for storage writes? ``` ``` -How do I use the Bank precompile to query a native denom balance? +How do I use the Bank precompile to query the native SEI (`usei`) balance? ``` ``` Load test my contract against the OCC parallel execution scheduler diff --git a/cosmos-sdk/index.mdx b/cosmos-sdk/index.mdx index c8f06d3..3e8e017 100644 --- a/cosmos-sdk/index.mdx +++ b/cosmos-sdk/index.mdx @@ -17,3 +17,11 @@ In addition, [Proposal 115](https://seistream.app/proposals/115) disables CosmWa **IBC is now disabled in both directions.** [Proposal 116](https://seistream.app/proposals/116) and [Proposal 120](https://seistream.app/proposals/120) set the `ibc` module's `InboundEnabled` parameter to `false`, and [Proposal 121](https://seistream.app/proposals/121) set `OutboundEnabled` to `false` on July 31, 2026. No asset can be bridged into or out of Sei over IBC, and IBC assets already on Sei can no longer be redeemed on their origin chain. See the [SIP-03 Migration Guide](/learn/sip-03-migration) for the full explanation and the list of affected assets. + +## Tokenfactory is not supported + + + +Tokenfactory tutorials and development support have been retired as part of Sei's move to EVM-only under SIP-3. Do not create, mint, burn, administer, or build integrations around tokenfactory denoms. Legacy module and RPC surfaces may still exist for compatibility, but tokenfactory is not a supported path for new development. Deploy an ERC-20 contract instead. + + diff --git a/docs.json b/docs.json index 7e3bc63..21acf25 100644 --- a/docs.json +++ b/docs.json @@ -658,6 +658,11 @@ "destination": "/learn/sip-03-migration#ibc-is-disabled", "permanent": true }, + { + "source": "/evm/precompiles/ibc", + "destination": "/learn/sip-03-migration#ibc-is-disabled", + "permanent": true + }, { "source": "/evm/precompiles/artifacts/:path*", "destination": "/evm/debugging-contracts", @@ -755,7 +760,7 @@ }, { "source": "/evm/ibc-protocol", - "destination": "/cosmos-sdk", + "destination": "/learn/sip-03-migration#ibc-is-disabled", "permanent": true }, { @@ -825,7 +830,7 @@ }, { "source": "/advanced/ibc-transfers", - "destination": "/cosmos-sdk", + "destination": "/learn/sip-03-migration#ibc-is-disabled", "permanent": true }, { @@ -1190,7 +1195,7 @@ }, { "source": "/dev-advanced-concepts/ibc-relayer", - "destination": "/cosmos-sdk", + "destination": "/learn/sip-03-migration#ibc-is-disabled", "permanent": true }, { @@ -1230,12 +1235,12 @@ }, { "source": "/dev-tutorials/tokenfactory-tutorial", - "destination": "/cosmos-sdk", + "destination": "/cosmos-sdk#tokenfactory-is-not-supported", "permanent": true }, { "source": "/dev-tutorials/tokenfactory-allowlist", - "destination": "/cosmos-sdk", + "destination": "/cosmos-sdk#tokenfactory-is-not-supported", "permanent": true }, { @@ -1255,7 +1260,7 @@ }, { "source": "/dev-tutorials/ibc-protocol", - "destination": "/cosmos-sdk", + "destination": "/learn/sip-03-migration#ibc-is-disabled", "permanent": true }, { @@ -1525,7 +1530,7 @@ }, { "source": "/cosmos-sdk/tokenfactory-allowlist", - "destination": "/learn/dev-token-standards", + "destination": "/cosmos-sdk#tokenfactory-is-not-supported", "permanent": true }, { diff --git a/evm/evm-parity/examples/pointer-contracts.mdx b/evm/evm-parity/examples/pointer-contracts.mdx index a44e324..ee29425 100644 --- a/evm/evm-parity/examples/pointer-contracts.mdx +++ b/evm/evm-parity/examples/pointer-contracts.mdx @@ -7,11 +7,14 @@ description: 'Looking up and interacting with pointer contracts that bridge Cosm Sei runs two token execution environments side by side — EVM and CosmWasm. Pointer contracts are automatically deployed EVM contracts that proxy a CosmWasm token, and vice versa. + +This guide covers pointers for already-deployed CosmWasm contracts only. It does not document native-denom pointer workflows. IBC is disabled in both directions, and tokenfactory is not a supported development path. See [IBC is disabled](/learn/sip-03-migration#ibc-is-disabled) and [Tokenfactory is not supported](/cosmos-sdk#tokenfactory-is-not-supported). + + | Token | Pointer type | EVM interface | | --- | --- | --- | | CW20 (CosmWasm fungible token) | ERC-20 pointer | Standard ERC-20 | | CW721 (CosmWasm NFT) | ERC-721 pointer | Standard ERC-721 | -| Native Sei token (bank module) | ERC-20 pointer | Standard ERC-20 | Once you have the pointer address, you interact with it using the standard ERC-20 or ERC-721 interface — no Sei-specific code needed. @@ -19,7 +22,7 @@ For background on how pointer contracts work, see the [Pointers overview](/learn ## Looking Up a Pointer Address -The pointerview precompile resolves pointer addresses by CosmWasm contract address or native denom. Its ABI and address are exported from `@sei-js/precompiles`. +The pointerview precompile resolves pointer addresses for existing CosmWasm contracts. Its ABI and address are exported from `@sei-js/precompiles`. @@ -48,14 +51,6 @@ const erc721Pointer = await client.readContract({ functionName: 'getCW721Pointer', args: ['sei1...cw721ContractAddress'], }); - -// Native denom → ERC-20 pointer -const nativePointer = await client.readContract({ - address: POINTERVIEW_PRECOMPILE_ADDRESS, - abi: POINTERVIEW_PRECOMPILE_ABI, - functionName: 'getNativePointer', - args: ['usei'], -}); ``` ```ts ethers @@ -78,9 +73,6 @@ const erc20Pointer = await pointerview.getCW20Pointer('sei1...cw20ContractAddres // CW721 → ERC-721 pointer const erc721Pointer = await pointerview.getCW721Pointer('sei1...cw721ContractAddress'); - -// Native denom → ERC-20 pointer -const nativePointer = await pointerview.getNativePointer('usei'); ``` diff --git a/evm/evm-parity/examples/sei-precompiles.mdx b/evm/evm-parity/examples/sei-precompiles.mdx index b170b93..5ad5207 100644 --- a/evm/evm-parity/examples/sei-precompiles.mdx +++ b/evm/evm-parity/examples/sei-precompiles.mdx @@ -9,7 +9,7 @@ Sei exposes native chain functionality through precompiled contracts at determin Available precompiles include: -- **Bank** — query native denom balances (usei, factory tokens) +- **Bank** — query the native SEI bank balance - **Staking** — delegate, undelegate, query delegations - **Distribution** — claim staking rewards - **Governance** — vote on active proposals diff --git a/evm/precompiles/cosmwasm-precompiles/bank.mdx b/evm/precompiles/cosmwasm-precompiles/bank.mdx index c83bb78..48b1021 100644 --- a/evm/precompiles/cosmwasm-precompiles/bank.mdx +++ b/evm/precompiles/cosmwasm-precompiles/bank.mdx @@ -1,1205 +1,138 @@ --- title: 'Bank Precompile' sidebarTitle: 'Bank' -description: "Learn how to interact with Sei's Bank precompile through ethers.js and Solidity, enabling native token transfers, balance queries, and token metadata management directly in your EVM smart contracts for seamless DeFi experiences." -keywords: ['bank precompile', 'token transfers', 'native sei', 'ethers.js', 'balance queries', 'sei development', 'defi', 'token metadata'] +description: "Query and transfer native SEI through Sei's Bank precompile." +keywords: ['bank precompile', 'native sei', 'ethers.js', 'balance query', 'sei development'] --- -**Address:** `0x0000000000000000000000000000000000001001` - -The Sei bank precompile allows EVM applications to interact directly with Sei's native banking system through standard smart contract calls. This enables querying balances, transferring tokens, and accessing token metadata for both native SEI tokens and Cosmos SDK-based assets, providing seamless integration between EVM and Cosmos ecosystems. - - **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 Bank Precompile Work? - -The bank precompile at address `0x0000000000000000000000000000000000001001` exposes functions like `send()`, `sendNative()`, `balance()`, `all_balances()`, and token metadata queries. - -- **Direct Integration:** EVM contracts and dApps can call banking functions like any other smart contract method. -- **Native Execution:** Operations are executed at the Cosmos SDK level for maximum efficiency and security. -- **Any native denom:** Manage native SEI and other bank module denominations from EVM contracts. -**When to use `send` vs `sendNative`:** `send` moves an arbitrary `denom` between two EVM addresses (`0x...`) by reading the balance directly from the bank module — no `msg.value` is attached. It is gated to the registered ERC20 native pointer for that denom, so it is typically invoked from the auto-deployed pointer contract rather than from arbitrary user code. `sendNative` is for sending native SEI (the attached `msg.value`) from the EVM caller to a Cosmos bech32 (`sei1...`) destination, which is useful for crossing the EVM→Cosmos boundary when the recipient has no associated EVM address (for example, paying a Cosmos-only contract or account). - -## Use Cases - -- **DeFi Applications:** Build decentralized finance protocols that can handle native SEI and Cosmos assets. -- **Portfolio Management:** Build tools to track and manage multi-asset portfolios across Cosmos and EVM. -- **Token Information Services:** Query comprehensive token metadata for UI display and analytics. - -## What You'll Learn in This Guide +**Address:** `0x0000000000000000000000000000000000001001` -By the end of this guide, you'll be able to: + +This page covers native SEI (`usei`) only. Do not use the Bank precompile as an IBC or tokenfactory integration path. IBC is disabled in both directions, and tokenfactory is not supported for new development. See [IBC is disabled](/learn/sip-03-migration#ibc-is-disabled) and [Tokenfactory is not supported](/cosmos-sdk#tokenfactory-is-not-supported). + -- **Execute Token Transfers** - Send both native SEI and custom tokens between addresses -- **Query Account Balances** - Check single and multi-asset balances for any address -- **Access Token Metadata** - Retrieve names, symbols, decimals, and supply information +The Bank precompile exposes the Bank Module balance for native SEI and lets an EVM caller send SEI to a native `sei1...` address. ## Functions -The bank precompile exposes the following functions: - -### Transaction Functions - ```solidity -/// Sends non-native tokens from one address to another. Callable only by the -/// registered ERC20 native pointer contract for the given denom. -/// @param fromAddress The EVM address (0x...) to send funds from. -/// @param toAddress The EVM address (0x...) to send funds to. -/// @param denom The denomination of funds to send. -/// @param amount The amount of the above denom to send. -/// @return success Whether the send was successfully executed. -function send( - address fromAddress, - address toAddress, - string memory denom, - uint256 amount -) external returns (bool success); - -/// Sends native SEI (the attached msg.value) from the EVM caller to a Cosmos -/// bech32 recipient. Requires a non-zero msg.value. -/// @param toNativeAddress The bech32 (sei1...) address of the recipient. -/// @return success Whether the tokens were successfully sent. -function sendNative( - string memory toNativeAddress -) payable external returns (bool success); -``` - -### Query Functions - -```solidity -/// Queries the balance of the given account for the specified denom. -/// @param acc The EVM address (0x...) of the account to query. -/// @param denom The denomination to query for. -/// @return amount The amount of denom held by acc. +/// Returns an account's Bank Module balance for the requested denomination. function balance( - address acc, + address account, string memory denom ) external view returns (uint256 amount); -/// Queries the balance of the given account for all balances. -/// @param acc The EVM address (0x...) of the account to query. -/// @return response Balances for all coins/denoms. -function all_balances( - address acc -) external view returns (Coin[] memory response); - -/// Queries the name of the specified denom. -/// @param denom The denomination to query about. -/// @return response The name of the specified denom. -function name( - string memory denom -) external view returns (string memory response); - -/// Queries the symbol of the specified denom. -/// @param denom The denomination to query about. -/// @return response The symbol of the specified denom. -function symbol( - string memory denom -) external view returns (string memory response); - -/// Queries the number of decimal places for the specified denom. -/// @param denom The denomination to query about. -/// @return response The number of decimals for the specified denom. -function decimals( - string memory denom -) external view returns (uint8 response); - -/// Queries the total supply of the specified denom. -/// @param denom The denomination to query about. -/// @return response The total supply of the specified denom. -function supply( - string memory denom -) external view returns (uint256 response); +/// Sends the attached native SEI to a native Sei address. +function sendNative( + string memory toNativeAddress +) external payable returns (bool success); ``` -## 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 testing transfers -- **Hardhat** for development and testing - -#### Install Dependencies +The examples below use `balance()` with `usei`. They do not cover arbitrary Bank Module denominations. -Install the required packages for interacting with Sei precompiles: +## Setup ```bash -# Instantiate a new Hardhat 3 project (choose "Hardhat 3" and the Mocha + Ethers.js TypeScript setup) -npx hardhat --init - -# 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 +npm install ethers @sei-js/precompiles ``` -#### Setup Hardhat Environment - -Create a `hardhat.config.ts` file with the following content: - ```typescript -import { defineConfig, configVariable } from 'hardhat/config'; -import hardhatToolboxMochaEthers from '@nomicfoundation/hardhat-toolbox-mocha-ethers'; - -export default defineConfig({ - solidity: '0.8.28', - networks: { - sei: { - type: 'http', - chainId: 1329, - url: 'https://evm-rpc.sei-apis.com', - accounts: [configVariable('PRIVATE_KEY')] - } - }, - plugins: [hardhatToolboxMochaEthers] -}); -``` - -Store your private key in Hardhat's encrypted keystore (no plaintext `.env` file needed): - -```bash -npx hardhat keystore set PRIVATE_KEY -``` - -#### Import Precompile Components - - - -```typescript -// Import Bank precompile address and ABI -// View the entire ABI here: https://github.com/sei-protocol/sei-chain/tree/main/precompiles/bank -import { BANK_PRECOMPILE_ABI, BANK_PRECOMPILE_ADDRESS } from '@sei-js/precompiles'; import { ethers } from 'ethers'; -``` - - - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -struct Coin { -uint256 amount; -string denom; -} - -interface IBankPrecompile { -function send( -address fromAddress, -address toAddress, -string memory denom, -uint256 amount -) external returns (bool success); - - function sendNative( - string memory toNativeAddress - ) payable external returns (bool success); - - function balance( - address acc, - string memory denom - ) external view returns (uint256 amount); - - function all_balances( - address acc - ) external view returns (Coin[] memory response); - - function name( - string memory denom - ) external view returns (string memory response); +import { + BANK_PRECOMPILE_ABI, + BANK_PRECOMPILE_ADDRESS, +} from '@sei-js/precompiles'; - function symbol( - string memory denom - ) external view returns (string memory response); - - function decimals( - string memory denom - ) external view returns (uint8 response); - - function supply( - string memory denom - ) external view returns (uint256 response); - -} - -```` - - - - **Precompile Address:** The bank precompile is deployed at `0x0000000000000000000000000000000000001001` - -### Contract Initialization - - - -Set up your provider, signer, and contract instance: - -```typescript -// 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 bank precompile -const bank = new ethers.Contract(BANK_PRECOMPILE_ADDRESS, BANK_PRECOMPILE_ABI, signer); -```` - - - -```solidity -// Initialize the contract instance in your Solidity code -contract TokenManager { - IBankPrecompile constant BANK = IBankPrecompile(0x0000000000000000000000000000000000001001); -} -``` - - - -### Native SEI vs Custom Tokens - -**Native SEI Transfers:** - -- Use `sendNative()` with payable value -- Denomination is always `usei` (micro-SEI) -- Parse to 18 digits when calling `sendNative()` - -**Custom Token Transfers:** - -- Use `send()` with specific denomination -- Requires prior token approval or ownership -- Support various decimal configurations - -## Step-by-Step Guide: Using the Bank Precompile - -### Send Native SEI Tokens - - - - -```typescript -// Send native SEI tokens to another address -const recipientAddress = 'sei1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6s8dpw'; -const amountInSei = '0.1'; // 0.1 SEI - -try { - // msg.value is in wei (18 decimals), like any other EVM transaction - const amountInWei = ethers.parseUnits(amountInSei, 18); // equivalent to ethers.parseEther(amountInSei) - - // Send native SEI - const tx = await bank.sendNative(recipientAddress, { - value: amountInWei, - gasLimit: 300000n - }); - - const receipt = await tx.wait(); - console.log('Native SEI transfer successful:', receipt.hash); - console.log(`Sent ${amountInSei} SEI to ${recipientAddress}`); -} catch (error) { - console.error('Native SEI transfer failed:', error); -} -``` - - - - -```solidity -contract PaymentProcessor { - IBankPrecompile constant BANK = IBankPrecompile(0x0000000000000000000000000000000000001001); - - event PaymentSent(address indexed from, string to, uint256 amount); - - function sendSeiPayment(string memory recipient) external payable { - require(msg.value > 0, "Payment amount must be greater than 0"); - - bool success = BANK.sendNative{value: msg.value}(recipient); - require(success, "Payment failed"); - - emit PaymentSent(msg.sender, recipient, msg.value); - } -} -``` - - - - -### Send Custom Tokens - - - - -`send()` can only be called by the registered ERC20 native pointer contract for the given denom — calling it from a regular wallet will revert. The snippet below only illustrates the arguments a pointer contract passes. As a user, transfer native denoms through the denom's ERC20 pointer contract (`transfer()`), or use `sendNative()` for SEI. - -```typescript -// Illustration: how a registered ERC20 pointer contract calls send() -const fromAddress = '0x1234567890123456789012345678901234567890'; -const toAddress = '0x9876543210987654321098765432109876543210'; -const tokenDenom = 'usei'; -const amount = '1'; - -// Amounts are in the denom's base units — check decimals() for each denom. -// usei has 6 decimals (1 SEI = 1,000,000 usei) -const tx = await bank.send( - fromAddress, - toAddress, - tokenDenom, - ethers.parseUnits(amount, 6), - { - gasLimit: 300000n - } +const readBank = new ethers.Contract( + BANK_PRECOMPILE_ADDRESS, + BANK_PRECOMPILE_ABI, + provider, ); -const receipt = await tx.wait(); -console.log('Custom token transfer successful:', receipt.hash); -console.log(`Sent ${amount} ${tokenDenom} from ${fromAddress} to ${toAddress}`); -``` - - - - -```solidity -contract TokenTransferManager { - IBankPrecompile constant BANK = IBankPrecompile(0x0000000000000000000000000000000000001001); - - event TokenTransfer( - address indexed from, - address indexed to, - string denom, - uint256 amount - ); - - function transferTokens( - address to, - string memory denom, - uint256 amount - ) external { - // Transfer tokens from sender to recipient - bool success = BANK.send(msg.sender, to, denom, amount); - require(success, "Token transfer failed"); - - emit TokenTransfer(msg.sender, to, denom, amount); - } - - function batchTransfer( - address[] memory recipients, - string memory denom, - uint256[] memory amounts - ) external { - require(recipients.length == amounts.length, "Array length mismatch"); - - for (uint256 i = 0; i < recipients.length; i++) { - bool success = BANK.send(msg.sender, recipients[i], denom, amounts[i]); - require(success, "Batch transfer failed"); - - emit TokenTransfer(msg.sender, recipients[i], denom, amounts[i]); - } - } -} +const writeBank = new ethers.Contract( + BANK_PRECOMPILE_ADDRESS, + BANK_PRECOMPILE_ABI, + signer, +); ``` - - - -### Query Account Balance +## Query a native SEI balance - - +Bank Module queries return native SEI in `usei`, where 1 SEI equals 1,000,000 `usei`. ```typescript -// Query specific token balance -const accountAddress = '0x1234567890123456789012345678901234567890'; -const tokenDenom = 'usei'; - -try { - const balance = await bank.balance(accountAddress, tokenDenom); +const account = '0x1234567890123456789012345678901234567890'; +const balanceUsei = await readBank.balance(account, 'usei'); - // Convert usei to SEI for display - if (tokenDenom === 'usei') { - const seiBalance = ethers.formatUnits(balance, 6); - console.log(`SEI Balance: ${seiBalance} SEI`); - } else { - console.log(`${tokenDenom} Balance: ${balance.toString()}`); - } -} catch (error) { - console.error('Balance query failed:', error); -} +console.log(`${ethers.formatUnits(balanceUsei, 6)} SEI`); ``` - - +You can make the same query from Solidity: ```solidity -contract BalanceChecker { - IBankPrecompile constant BANK = IBankPrecompile(0x0000000000000000000000000000000000001001); - - function getUserSeiBalance(address user) external view returns (uint256) { - return BANK.balance(user, "usei"); - } +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; - function getUserTokenBalance( - address user, +interface IBankPrecompile { + function balance( + address account, string memory denom - ) external view returns (uint256) { - return BANK.balance(user, denom); - } - - function hasMinimumBalance( - address user, - string memory denom, - uint256 minAmount - ) external view returns (bool) { - uint256 balance = BANK.balance(user, denom); - return balance >= minAmount; - } -} -``` - - - - -### Query All Balances - - - - -```typescript -// Query all token balances for an account -const accountAddress = '0x1234567890123456789012345678901234567890'; - -try { - const allBalances = await bank.all_balances(accountAddress); - - console.log(`Account: ${accountAddress}`); - console.log('All Balances:'); - - allBalances.forEach((coin, index) => { - if (coin.denom === 'usei') { - const seiAmount = ethers.formatUnits(coin.amount, 6); - console.log(` ${index + 1}. ${seiAmount} SEI (${coin.denom})`); - } else { - console.log(` ${index + 1}. ${coin.amount.toString()} ${coin.denom}`); - } - }); -} catch (error) { - console.error('All balances query failed:', error); -} -``` - - - - -```solidity -contract PortfolioManager { - IBankPrecompile constant BANK = IBankPrecompile(0x0000000000000000000000000000000000001001); - - struct Portfolio { - address owner; - Coin[] balances; - uint256 totalValue; // In usei equivalent - } - - function getPortfolio(address user) external view returns (Coin[] memory) { - return BANK.all_balances(user); - } - - function hasAnyBalance(address user) external view returns (bool) { - Coin[] memory balances = BANK.all_balances(user); - return balances.length > 0; - } - - function countTokenTypes(address user) external view returns (uint256) { - Coin[] memory balances = BANK.all_balances(user); - return balances.length; - } - - function findTokenBalance( - address user, - string memory targetDenom - ) external view returns (uint256) { - Coin[] memory balances = BANK.all_balances(user); - - for (uint256 i = 0; i < balances.length; i++) { - if (keccak256(bytes(balances[i].denom)) == keccak256(bytes(targetDenom))) { - return balances[i].amount; - } - } - - return 0; // Token not found - } -} -``` - - - - -### Query Token Metadata - - - - -```typescript -// Query comprehensive token metadata -const tokenDenom = 'usei'; - -try { - // Get all metadata in parallel - const [name, symbol, decimals, totalSupply] = await Promise.all([bank.name(tokenDenom), bank.symbol(tokenDenom), bank.decimals(tokenDenom), bank.supply(tokenDenom)]); - - console.log('Token Metadata:'); - console.log(` Denomination: ${tokenDenom}`); - console.log(` Name: ${name}`); - console.log(` Symbol: ${symbol}`); - console.log(` Decimals: ${decimals}`); - console.log(` Total Supply: ${ethers.formatUnits(totalSupply, decimals)}`); -} catch (error) { - console.error('Metadata query failed:', error); -} - -// Function to get formatted token info -async function getTokenInfo(denom) { - try { - const metadata = { - denom: denom, - name: await bank.name(denom), - symbol: await bank.symbol(denom), - decimals: await bank.decimals(denom), - supply: await bank.supply(denom) - }; - - return { - ...metadata, - formattedSupply: ethers.formatUnits(metadata.supply, metadata.decimals) - }; - } catch (error) { - console.error(`Failed to get info for ${denom}:`, error); - return null; - } + ) external view returns (uint256 amount); } -``` - - - -```solidity -contract TokenRegistry { - IBankPrecompile constant BANK = IBankPrecompile(0x0000000000000000000000000000000000001001); +contract SeiBalanceReader { + IBankPrecompile private constant BANK = + IBankPrecompile(0x0000000000000000000000000000000000001001); - struct TokenInfo { - string denom; - string name; - string symbol; - uint8 decimals; - uint256 totalSupply; - bool isValid; - } - - mapping(string => TokenInfo) public tokenRegistry; - - function getTokenInfo( - string memory denom - ) external view returns (TokenInfo memory) { - TokenInfo memory info; - - info.denom = denom; - info.name = BANK.name(denom); - info.symbol = BANK.symbol(denom); - info.decimals = BANK.decimals(denom); - info.totalSupply = BANK.supply(denom); - info.isValid = true; - - return info; + function nativeSeiBalance(address account) external view returns (uint256) { + return BANK.balance(account, "usei"); } } ``` - - - -### Complete Integration Example +## Send native SEI to a native address - - +`sendNative()` accepts SEI through `msg.value`. Use an 18-decimal EVM value for the transaction. ```typescript -import { BANK_PRECOMPILE_ABI, BANK_PRECOMPILE_ADDRESS } from '@sei-js/precompiles'; -import { ethers } from 'ethers'; - -class SeiTokenManager { - private bank: ethers.Contract; - private signer: ethers.Signer; - - constructor(signer: ethers.Signer) { - this.signer = signer; - this.bank = new ethers.Contract(BANK_PRECOMPILE_ADDRESS, BANK_PRECOMPILE_ABI, signer); - } - - // Send native SEI tokens - async sendSei(recipientAddress: string, amountInSei: string) { - try { - const amountInWei = ethers.parseUnits(amountInSei, 18); - const tx = await this.bank.sendNative(recipientAddress, { - value: amountInWei, - gasLimit: 100000 - }); +const recipient = 'sei1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6s8dpw'; - const receipt = await tx.wait(); - return { - success: true, - transactionHash: receipt.hash, - amount: amountInSei, - recipient: recipientAddress - }; - } catch (error) { - return { success: false, error: error.message }; - } - } - - // Get user's portfolio - async getPortfolio(address: string) { - try { - const balances = await this.bank.all_balances(address); - const portfolio = []; - - for (const coin of balances) { - try { - const metadata = await this.getTokenMetadata(coin.denom); - portfolio.push({ - denom: coin.denom, - amount: coin.amount.toString(), - formattedAmount: ethers.formatUnits(coin.amount, metadata.decimals), - ...metadata - }); - } catch (metadataError) { - // If metadata fails, still include the balance - portfolio.push({ - denom: coin.denom, - amount: coin.amount.toString(), - formattedAmount: coin.amount.toString(), - name: 'Unknown', - symbol: 'Unknown', - decimals: 0 - }); - } - } - - return { success: true, portfolio }; - } catch (error) { - return { success: false, error: error.message }; - } - } - - // Get token metadata - async getTokenMetadata(denom: string) { - const [name, symbol, decimals, supply] = await Promise.all([this.bank.name(denom).catch(() => 'Unknown'), this.bank.symbol(denom).catch(() => 'Unknown'), this.bank.decimals(denom).catch(() => 0), this.bank.supply(denom).catch(() => 0n)]); - - return { name, symbol, decimals, supply: supply.toString() }; - } - - // Transfer custom tokens - async transferToken(toAddress: string, denom: string, amount: string, decimals: number = 18) { - try { - const fromAddress = await this.signer.getAddress(); - const parsedAmount = ethers.parseUnits(amount, decimals); - - const tx = await this.bank.send(fromAddress, toAddress, denom, parsedAmount, { - gasLimit: 150000 - }); - - const receipt = await tx.wait(); - return { - success: true, - transactionHash: receipt.hash, - from: fromAddress, - to: toAddress, - denom, - amount - }; - } catch (error) { - return { success: false, error: error.message }; - } - } - - // Batch operations - async batchBalanceCheck(addresses: string[], denom: string) { - try { - const balances = await Promise.allSettled(addresses.map((addr) => this.bank.balance(addr, denom))); - - return balances.map((result, index) => ({ - address: addresses[index], - balance: result.status === 'fulfilled' ? result.value.toString() : '0', - success: result.status === 'fulfilled' - })); - } catch (error) { - throw new Error(`Batch balance check failed: ${error.message}`); - } - } -} - -// Usage example -async function bankExample() { - const provider = new ethers.BrowserProvider(window.ethereum); - await provider.send('eth_requestAccounts', []); - const signer = await provider.getSigner(); - const tokenManager = new SeiTokenManager(signer); - - console.log('=== Sei Token Manager Demo ==='); - - // 1. Get current user's portfolio - const userAddress = await signer.getAddress(); - const portfolio = await tokenManager.getPortfolio(userAddress); - - if (portfolio.success) { - console.log('User Portfolio:'); - portfolio.portfolio.forEach((token, index) => { - console.log(` ${index + 1}. ${token.formattedAmount} ${token.symbol} (${token.name})`); - }); - } - - // 2. Send native SEI - const sendResult = await tokenManager.sendSei('sei1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6s8dpw', '0.01'); - - if (sendResult.success) { - console.log('SEI transfer successful:', sendResult.transactionHash); - } - - // 3. Check balances for multiple addresses - const addresses = ['0x1234567890123456789012345678901234567890', '0x9876543210987654321098765432109876543210']; +const transaction = await writeBank.sendNative(recipient, { + value: ethers.parseEther('0.1'), +}); - const batchBalances = await tokenManager.batchBalanceCheck(addresses, 'usei'); - console.log('Batch balance results:', batchBalances); -} +await transaction.wait(); ``` - - - -**Complete Contract Example** +From Solidity, forward the attached value to the precompile: ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.20; interface IBankPrecompile { - function send(address fromAddress, address toAddress, string memory denom, uint256 amount) external returns (bool success); - function sendNative(string memory toNativeAddress) payable external returns (bool success); - function balance(address acc, string memory denom) external view returns (uint256 amount); - function all_balances(address acc) external view returns (Coin[] memory response); - function name(string memory denom) external view returns (string memory response); - function symbol(string memory denom) external view returns (string memory response); - function decimals(string memory denom) external view returns (uint8 response); - function supply(string memory denom) external view returns (uint256 response); -} - -struct Coin { - uint256 amount; - string denom; + function sendNative( + string memory toNativeAddress + ) external payable returns (bool success); } -contract ComprehensiveTokenManager { - IBankPrecompile constant BANK = IBankPrecompile(0x0000000000000000000000000000000000001001); - - // Events - event PaymentProcessed(address indexed from, string to, uint256 amount, string denom); - event TokenTransfer(address indexed from, address indexed to, string denom, uint256 amount); - event BatchTransferCompleted(address indexed sender, uint256 totalRecipients); - - // State variables - mapping(address => bool) public authorizedOperators; - mapping(string => bool) public supportedTokens; - address public owner; - - modifier onlyOwner() { - require(msg.sender == owner, "Only owner can execute"); - _; - } - - modifier onlyAuthorized() { - require(authorizedOperators[msg.sender] || msg.sender == owner, "Not authorized"); - _; - } - - constructor() { - owner = msg.sender; - authorizedOperators[msg.sender] = true; - supportedTokens["usei"] = true; - } - - // ============= - // Payment Functions - // ============= - - function processPayment( - string memory recipient, - uint256 amount - ) external payable { - require(msg.value >= amount, "Insufficient payment"); - - bool success = BANK.sendNative{value: amount}(recipient); - require(success, "Payment failed"); - - // Refund excess - if (msg.value > amount) { - payable(msg.sender).transfer(msg.value - amount); - } - - emit PaymentProcessed(msg.sender, recipient, amount, "usei"); - } - - function processTokenPayment( - address recipient, - string memory denom, - uint256 amount - ) external onlyAuthorized { - require(supportedTokens[denom], "Token not supported"); - - bool success = BANK.send(msg.sender, recipient, denom, amount); - require(success, "Token payment failed"); - - emit TokenTransfer(msg.sender, recipient, denom, amount); - } - - // ============= - // Batch Operations - // ============= +contract NativeSeiSender { + IBankPrecompile private constant BANK = + IBankPrecompile(0x0000000000000000000000000000000000001001); - function batchSeiTransfer( - string[] memory recipients, - uint256[] memory amounts + function sendToNativeAddress( + string calldata recipient ) external payable { - require(recipients.length == amounts.length, "Array length mismatch"); - require(recipients.length <= 50, "Too many recipients"); - - uint256 totalAmount = 0; - for (uint256 i = 0; i < amounts.length; i++) { - totalAmount += amounts[i]; - } - require(msg.value >= totalAmount, "Insufficient total payment"); - - for (uint256 i = 0; i < recipients.length; i++) { - bool success = BANK.sendNative{value: amounts[i]}(recipients[i]); - require(success, "Batch transfer failed"); - - emit PaymentProcessed(msg.sender, recipients[i], amounts[i], "usei"); - } - - // Refund excess - if (msg.value > totalAmount) { - payable(msg.sender).transfer(msg.value - totalAmount); - } - - emit BatchTransferCompleted(msg.sender, recipients.length); - } - - function batchTokenTransfer( - address[] memory recipients, - string memory denom, - uint256[] memory amounts - ) external onlyAuthorized { - require(recipients.length == amounts.length, "Array length mismatch"); - require(recipients.length <= 20, "Too many recipients"); - require(supportedTokens[denom], "Token not supported"); - - for (uint256 i = 0; i < recipients.length; i++) { - bool success = BANK.send(msg.sender, recipients[i], denom, amounts[i]); - require(success, "Batch token transfer failed"); - - emit TokenTransfer(msg.sender, recipients[i], denom, amounts[i]); - } - - emit BatchTransferCompleted(msg.sender, recipients.length); - } - - // ============= - // Query Functions - // ============= - - function getUserPortfolio(address user) external view returns (Coin[] memory) { - return BANK.all_balances(user); - } - - function getUserBalance(address user, string memory denom) external view returns (uint256) { - return BANK.balance(user, denom); - } - - function getTokenInfo(string memory denom) external view returns ( - string memory name, - string memory symbol, - uint8 decimals, - uint256 totalSupply - ) { - name = BANK.name(denom); - symbol = BANK.symbol(denom); - decimals = BANK.decimals(denom); - totalSupply = BANK.supply(denom); - } - - function checkSufficientBalance( - address user, - string memory denom, - uint256 requiredAmount - ) external view returns (bool) { - uint256 balance = BANK.balance(user, denom); - return balance >= requiredAmount; - } - - function batchBalanceCheck( - address[] memory users, - string memory denom - ) external view returns (uint256[] memory balances) { - balances = new uint256[](users.length); - for (uint256 i = 0; i < users.length; i++) { - balances[i] = BANK.balance(users[i], denom); - } + require(msg.value > 0, "No SEI attached"); + require( + BANK.sendNative{value: msg.value}(recipient), + "Transfer failed" + ); } - - // ============= - // Admin Functions - // ============= - - function addSupportedToken(string memory denom) external onlyOwner { - supportedTokens[denom] = true; - } - - function removeSupportedToken(string memory denom) external onlyOwner { - supportedTokens[denom] = false; - } - - function addOperator(address operator) external onlyOwner { - authorizedOperators[operator] = true; - } - - function removeOperator(address operator) external onlyOwner { - require(operator != owner, "Cannot remove owner"); - authorizedOperators[operator] = false; - } - - // Emergency withdraw function - function emergencyWithdraw() external onlyOwner { - payable(owner).transfer(address(this).balance); - } - - // ============= - // Utility Functions - // ============= - - function convertSeiToUsei(uint256 seiAmount) pure external returns (uint256) { - return seiAmount * 1e6; - } - - function convertUseiToSei(uint256 useiAmount) pure external returns (uint256) { - return useiAmount / 1e6; - } - - receive() external payable {} } ``` -Compile the contract: - -```bash -npx hardhat compile -``` - -**Deployment Script** - -First, deploy the contract using Hardhat: - -```javascript -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() { - // The signer comes from the network config (encrypted keystore) - const [deployer] = await ethers.getSigners(); - console.log('Deploying contracts with the account:', deployer.address); - - const balance = await deployer.provider.getBalance(deployer.address); - console.log('Account balance:', ethers.formatEther(balance)); - - const ComprehensiveTokenManager = await ethers.getContractFactory('ComprehensiveTokenManager'); - console.log('Deploying ComprehensiveTokenManager...', ComprehensiveTokenManager); - const comprehensiveTokenManager = await ComprehensiveTokenManager.deploy({ - gasLimit: 5000000n // Set a reasonable gas limit - }); - await comprehensiveTokenManager.waitForDeployment(); - - console.log('ComprehensiveTokenManager deployed to:', await comprehensiveTokenManager.getAddress()); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); -``` - -To deploy, run: - -```bash -npx hardhat run scripts/deploy.js --network sei -``` - -Next look through the integration example: - -```javascript -import { network } from 'hardhat'; -import TokenManager from './artifacts/contracts/ComprehensiveTokenManager.sol/ComprehensiveTokenManager.json' with { type: 'json' }; - -// Hardhat 3 exposes ethers through a network connection rather than a global import -const { ethers } = await network.create(); - -async function main() { - // The signer comes from the network config (encrypted keystore) - const [deployer] = await ethers.getSigners(); - console.log('Interacting with the account:', deployer.address); - - const address = '0xYourDeployedContractAddress'; // Replace with your contract address - const tokenManager = new ethers.Contract(address, TokenManager.abi, deployer); - console.log('TokenManager deployed to:', address); - - // Add some supported tokens - const tokens = ['usei', 'uatom', 'ubtc']; - - for (const token of tokens) { - try { - const tx = await tokenManager.addSupportedToken(token); - await tx.wait(); - console.log('Added supported token:', token); - } catch (error) { - console.error('Failed to add token:', token, error.message); - } - } - - try { - const allBalances = await tokenManager.getUserPortfolio(deployer.address); - console.log('All balances:', allBalances); - } catch (error) { - console.error('Failed to get user portfolio:', error.message); - } -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); -``` - -Then run the integration example: - -```bash -npx hardhat run scripts/integrationExample.js --network sei -``` - - - - -## Security Considerations & Risks - -### Transaction Security - -- **Amount Validation:** Always validate transfer amounts and ensure sufficient balances -- **Address Verification:** Verify recipient addresses are valid before sending tokens -- **Reentrancy Protection:** Be aware of potential reentrancy when combining with other contracts - -### Permission Management - -```solidity -// Example of secure permission patterns -modifier onlyTokenHolder(string memory denom, uint256 minAmount) { - require(BANK.balance(msg.sender, denom) >= minAmount, "Insufficient token balance"); - _; -} - -modifier validRecipient(address recipient) { - require(recipient != address(0), "Invalid recipient"); - require(recipient != address(this), "Cannot send to contract"); - _; -} -``` - -## Troubleshooting - -### Common Issues and Solutions - -#### Transaction Failures - -```typescript -// Handle common transfer errors -try { - const tx = await bank.sendNative(recipient, { value: amount }); - await tx.wait(); -} catch (error) { - if (error.message.includes('insufficient funds')) { - console.error('Insufficient balance for transfer'); - } else if (error.message.includes('invalid address')) { - console.error('Invalid recipient address format'); - } else { - console.error('Transfer failed:', error.message); - } -} -``` - -#### Balance Query Issues - -```typescript -// Safe balance checking with error handling -async function safeGetBalance(address: string, denom: string) { - try { - const balance = await bank.balance(address, denom); - return { success: true, balance: balance.toString() }; - } catch (error) { - if (error.message.includes('not found')) { - return { success: true, balance: '0' }; // No balance = 0 - } - return { success: false, error: error.message }; - } -} -``` - -### Error Code Reference - -| Error | Cause | Solution | -| --- | --- | --- | -| `insufficient funds` | Not enough balance for transfer | Check balance before transfer | -| `invalid address` | Malformed address format | Use proper EVM (0x...) or Sei (sei1...) format | -| `unknown denomination` | Token denom doesn't exist | Verify token denomination format | -| `amount overflow` | Amount exceeds uint256 limits | Use appropriate amount ranges | -| `metadata not found` | Token metadata not available | Handle missing metadata gracefully | - - -## Important Notes - - - -**Remember:** Always verify token denominations and handle errors gracefully in production applications! - -- **SEI Native:** While reading from chain it is formatted to 6 decimal places (1 SEI = 1,000,000 usei) and while writing to chain it is parsed to 18 decimal places. -- **Custom Tokens:** Check decimals using `decimals()` function -- **Display Formatting:** Always format amounts with proper decimal places for user display - - - -### Gas Optimization - -- **Batch Operations:** Use batch functions for multiple operations to save gas -- **Query Efficiency:** Cache frequently accessed token metadata -- **Error Handling:** Implement proper error handling to avoid failed transaction costs - -### Integration Best Practices - -- **Balance Checks:** Always verify sufficient balance before transfers -- **Error Recovery:** Implement retry logic for failed transactions -- **User Experience:** Provide clear feedback on transaction status -- **Decimal Handling:** Use proper decimal formatting for different token types - -View the Bank precompile source code and the contract ABI [here](https://github.com/sei-protocol/sei-chain/tree/main/precompiles/bank). +Validate the recipient before sending. A successful transaction cannot be reversed. diff --git a/evm/precompiles/cosmwasm-precompiles/cosmwasm.mdx b/evm/precompiles/cosmwasm-precompiles/cosmwasm.mdx index 8048e3c..d0e82e8 100644 --- a/evm/precompiles/cosmwasm-precompiles/cosmwasm.mdx +++ b/evm/precompiles/cosmwasm-precompiles/cosmwasm.mdx @@ -11,6 +11,8 @@ keywords: ['cosmwasm precompile', 'ethers.js', 'wasm execution', 'cross-chain co Per [governance Proposal 115](https://seistream.app/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). + The examples on this page attach only native SEI. Do not use the `coins` field to build IBC or tokenfactory integrations. IBC is disabled in both directions, and tokenfactory is not a supported development path. + For new smart contract development, use the EVM directly. See [Deploy a Smart Contract](/evm/evm-general). @@ -47,7 +49,7 @@ The CosmWasm precompile exposes the following functions: /// 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. +/// @param coins A JSON-encoded coin list required by the legacy ABI. /// @return response The execution response from the CosmWasm contract. function execute( string memory contractAddress, @@ -153,10 +155,10 @@ The CosmWasm precompile requires **JSON-encoded messages** that conform to each - `execute()` - accepts execution message as JSON bytes - `query()` - accepts query message as JSON bytes -**Native Token Handling:** +**Native SEI handling:** - Use `msg.value` for SEI amounts -- Use `coins` parameter for other denominations (encoded as JSON bytes) +- Pass an empty JSON array for `coins` when the call does not require Bank Module funds ### Best Practice: Message Encoding Helpers @@ -175,12 +177,6 @@ class CosmWasmMessageEncoder { 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); @@ -218,12 +214,9 @@ class CosmWasmHelper { 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)); + // Create the empty coin list used by these examples + static emptyCoins(): Uint8Array { + return ethers.toUtf8Bytes('[]'); } // Parse response from CosmWasm contract @@ -246,7 +239,7 @@ const executeMsg = CosmWasmHelper.createExecuteMsg({ } }); -const coins = CosmWasmHelper.createCoins([{ denom: 'uusdc', amount: '1000000' }]); +const coins = CosmWasmHelper.emptyCoins(); ``` ## Step-by-Step Guide: Using the CosmWasm Precompile @@ -269,7 +262,7 @@ const executeMsg = CosmWasmHelper.createExecuteMsg({ }); // No additional coins needed for this execution -const coins = CosmWasmHelper.createCoins([]); +const coins = CosmWasmHelper.emptyCoins(); const tx = await cosmwasm.execute(contractAddress, executeMsg, coins); @@ -339,12 +332,12 @@ const executeMsgs = [ { contractAddress: contract1, msg: executeMsg1, - coins: CosmWasmHelper.createCoins([]) + coins: CosmWasmHelper.emptyCoins() }, { contractAddress: contract2, msg: executeMsg2, - coins: CosmWasmHelper.createCoins([]) + coins: CosmWasmHelper.emptyCoins() } ]; @@ -467,7 +460,7 @@ async function crossRuntimeDeFiOperation(cosmwasmDexContract: string, evmTokenCo } }); - const swapTx = await cosmwasm.execute(cosmwasmDexContract, swapMsg, CosmWasmHelper.createCoins([]), { value: ethers.parseEther(amount) }); + const swapTx = await cosmwasm.execute(cosmwasmDexContract, swapMsg, CosmWasmHelper.emptyCoins(), { value: ethers.parseEther(amount) }); await swapTx.wait(); console.log('CosmWasm swap completed'); @@ -518,7 +511,7 @@ async function cosmwasmExample() { } }); - const mintTx = await cosmwasm.execute(contractAddress, mintMsg, CosmWasmHelper.createCoins([])); + const mintTx = await cosmwasm.execute(contractAddress, mintMsg, CosmWasmHelper.emptyCoins()); await mintTx.wait(); console.log('Tokens minted successfully'); @@ -555,7 +548,7 @@ async function cosmwasmExample() { amount: '100000000' // 100 tokens } }), - coins: CosmWasmHelper.createCoins([]) + coins: CosmWasmHelper.emptyCoins() }, { contractAddress: contractAddress, @@ -565,7 +558,7 @@ async function cosmwasmExample() { amount: '200000000' // 200 tokens } }), - coins: CosmWasmHelper.createCoins([]) + coins: CosmWasmHelper.emptyCoins() } ]; @@ -780,7 +773,7 @@ const incorrectMsg = ethers.toUtf8Bytes('invalid json'); - **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 +- **Native SEI Handling:** Use `msg.value` for SEI and leave the `coins` list empty - **Batch Limitations:** Large batches may hit gas limits ### Best Practices diff --git a/evm/precompiles/cosmwasm-precompiles/example-usage.mdx b/evm/precompiles/cosmwasm-precompiles/example-usage.mdx index c30eaa6..5fe3cd6 100644 --- a/evm/precompiles/cosmwasm-precompiles/example-usage.mdx +++ b/evm/precompiles/cosmwasm-precompiles/example-usage.mdx @@ -92,7 +92,7 @@ const overrides = { const executeResponse = await contract.execute( COUNTER_CONTRACT_ADDRESS, toUtf8Bytes(JSON.stringify(executeMsg)), - toUtf8Bytes(JSON.stringify([{ denom: 'uusdc', amount: '100' }])), // Also send 100 uusdc + toUtf8Bytes(JSON.stringify([])), // No Bank Module funds attached overrides ); @@ -100,5 +100,4 @@ await executeResponse.wait(); const receipt = await provider.getTransactionReceipt(executeResponse.hash); ``` -For payable contracts, Sei amounts have to be sent directly to the contract -while other denoms should use the `coins` field. +For payable contracts, attach native SEI through `msg.value`. diff --git a/evm/precompiles/example-usage.mdx b/evm/precompiles/example-usage.mdx index 4698939..e620dd4 100644 --- a/evm/precompiles/example-usage.mdx +++ b/evm/precompiles/example-usage.mdx @@ -12,7 +12,7 @@ Sei precompiles are special smart contracts deployed at fixed addresses that exp | Precompile | Address | Description | | --- | --- | --- | -| Bank | `0x1001` | Query native denom balances (usei, factory tokens) | +| Bank | `0x1001` | Query the native SEI bank balance | | JSON | `0x1003` | Parse JSON data within contracts | | Staking | `0x1005` | Delegation and staking operations | | Governance | `0x1006` | Proposal voting | @@ -56,7 +56,7 @@ const signer = await provider.getSigner(); ## Bank Precompile -`eth_getBalance` only returns the EVM-side SEI balance. The Bank precompile lets you query any native denom — including factory tokens — from any address: +`eth_getBalance` only returns the EVM-side SEI balance. The Bank precompile lets you query the native SEI (`usei`) bank balance for an address: @@ -70,15 +70,6 @@ const balance = await client.readContract({ functionName: 'balance', args: ['0xYourAddress', 'usei'], }); - -// Query all native balances for an address -const allBalances = await client.readContract({ - address: BANK_PRECOMPILE_ADDRESS, - abi: BANK_PRECOMPILE_ABI, - functionName: 'all_balances', - args: ['0xYourAddress'], -}); -// Returns: [{ denom: 'usei', amount: '1000000' }, ...] ``` ```ts ethers @@ -87,7 +78,6 @@ import { BANK_PRECOMPILE_ABI, BANK_PRECOMPILE_ADDRESS } from '@sei-js/precompile const bank = new ethers.Contract(BANK_PRECOMPILE_ADDRESS, BANK_PRECOMPILE_ABI, provider); const balance = await bank.balance('0xYourAddress', 'usei'); -const allBalances = await bank.all_balances('0xYourAddress'); ``` diff --git a/evm/sei-js/index.mdx b/evm/sei-js/index.mdx index c478937..a213e55 100644 --- a/evm/sei-js/index.mdx +++ b/evm/sei-js/index.mdx @@ -106,7 +106,7 @@ End-to-end code examples using viem and ethers with Sei: Batch multiple contract reads into a single RPC call with Multicall3 and viem/ethers/wagmi. - Look up CW20/CW721/native pointer addresses and interact with CosmWasm tokens via ERC interfaces. + Look up pointer addresses for existing CW20 and CW721 contracts, then interact with them through ERC interfaces. Native balances, staking, rewards, and governance voting from JavaScript. diff --git a/evm/sei-js/registry.mdx b/evm/sei-js/registry.mdx index db5e5c1..d1b3c3f 100644 --- a/evm/sei-js/registry.mdx +++ b/evm/sei-js/registry.mdx @@ -69,10 +69,14 @@ async function getWorkingRpc(network: 'pacific-1' | 'atlantic-2' | 'arctic-1') { Token registry per network — name, symbol, base denom, decimal exponents, images, and CoinGecko IDs: + +The registry may retain legacy IBC or tokenfactory entries for display and compatibility. Their presence does not mean they are supported integration targets. IBC is disabled in both directions, and tokenfactory is not supported for new development. + + ```ts import { TOKEN_LIST } from '@sei-js/registry'; -// All tokens on mainnet +// Registry metadata on mainnet const tokens = TOKEN_LIST['pacific-1']; // Find SEI @@ -84,11 +88,6 @@ function toDisplayAmount(usei: bigint, token: typeof sei): string { const exp = token.denom_units.find(u => u.denom === token.display)?.exponent ?? 6; return (Number(usei) / 10 ** exp).toString(); } - -// Look up a token by its on-chain denom -function findByDenom(denom: string) { - return TOKEN_LIST['pacific-1'].find(t => t.base === denom); -} ``` Each token includes an `images` object with `png` and `svg` URLs suitable for display in wallet UIs or token pickers. diff --git a/learn/dev-interoperability.mdx b/learn/dev-interoperability.mdx index a428139..4d9d239 100644 --- a/learn/dev-interoperability.mdx +++ b/learn/dev-interoperability.mdx @@ -6,7 +6,7 @@ keywords: ['blockchain interoperability', 'EVM Cosmos bridge', 'dual address sys --- - **CosmWasm deployments are frozen, and IBC is disabled in both directions.** Per [Proposal 115](https://seistream.app/proposals/115), no new CosmWasm contracts can be uploaded or instantiated on Sei. Proposals [116](https://seistream.app/proposals/116), [120](https://seistream.app/proposals/120), and [121](https://seistream.app/proposals/121) disabled inbound and then outbound IBC transfers, so no asset can be bridged into or out of Sei over IBC. The interoperability features described on this page apply to **already-deployed** CosmWasm contracts, native Bank Module assets, and Cosmos-SDK modules accessed via precompiles. For new smart contract development, build directly on the EVM. See [SIP-3](https://github.com/sei-protocol/sips/blob/main/sips/sip-3.md) and the [SIP-03 Migration Guide](/learn/sip-03-migration) for the full migration context. + **CosmWasm deployments are frozen, and IBC is disabled in both directions.** Per [Proposal 115](https://seistream.app/proposals/115), no new CosmWasm contracts can be uploaded or instantiated on Sei. Proposals [116](https://seistream.app/proposals/116), [120](https://seistream.app/proposals/120), and [121](https://seistream.app/proposals/121) disabled inbound and then outbound IBC transfers, so no asset can be bridged into or out of Sei over IBC. The interoperability features described on this page apply to **already-deployed** CosmWasm contracts, native Bank Module assets, and Cosmos-SDK modules accessed via precompiles. Tokenfactory is not a supported development path, and you should not use native-denom pointers or Bank Module interfaces to build tokenfactory integrations. For new smart contract development, build directly on the EVM. See [SIP-3](https://github.com/sei-protocol/sips/blob/main/sips/sip-3.md), [Tokenfactory is not supported](/cosmos-sdk#tokenfactory-is-not-supported), and the [SIP-03 Migration Guide](/learn/sip-03-migration). ## Dual Address Support diff --git a/learn/dev-token-standards.mdx b/learn/dev-token-standards.mdx index 24ee537..daa7ba5 100644 --- a/learn/dev-token-standards.mdx +++ b/learn/dev-token-standards.mdx @@ -8,6 +8,10 @@ keywords: ['token standards', 'erc20', 'cw20', 'nfts'] **Use ERC20 / ERC721 / ERC1155 for new tokens.** Per [Proposal 115](https://seistream.app/proposals/115), CosmWasm code uploads and contract instantiations are disabled on Sei, so no new CW20 / CW721 / CW1155 tokens can be deployed. The CW standards described below are documented for users and developers interacting with already-deployed legacy contracts. + + **Do not use tokenfactory for new tokens or integrations.** Tokenfactory tutorials and development support have been retired. Legacy module surfaces may remain available for compatibility, but tokenfactory is not a supported development path. Use ERC20 for new fungible tokens. See [Tokenfactory is not supported](/cosmos-sdk#tokenfactory-is-not-supported). + + In this section, we delve into the various token standards supported on Sei. Understanding these standards is crucial for developers as they form the foundation of many decentralized applications. diff --git a/learn/pointers.mdx b/learn/pointers.mdx index c4c832e..0e6a743 100644 --- a/learn/pointers.mdx +++ b/learn/pointers.mdx @@ -5,9 +5,9 @@ description: "Understand how Sei's pointer contract system enables seamless asse keywords: ['pointer contracts', 'cross-vm interoperability', 'evm cosmos bridge', 'token bridging', 'smart contract integration'] --- - - **Pointer contracts are now primarily a legacy / migration tool.** Per [Proposal 115](https://seistream.app/proposals/115), no new CosmWasm contracts can be uploaded or instantiated on Sei, so the CW20 / CW721 / CW1155 → ERC20 / ERC721 / ERC1155 pointer flow only applies to already-deployed CosmWasm contracts. Native (Bank Module) pointers continue to work normally. For new tokens or NFTs, deploy ERC20 / ERC721 / ERC1155 contracts directly on the EVM. - + + **Pointer contracts are now primarily a legacy and migration tool.** Per [Proposal 115](https://seistream.app/proposals/115), no new CosmWasm contracts can be uploaded or instantiated on Sei, so the CW20 / CW721 / CW1155 to ERC20 / ERC721 / ERC1155 pointer flow only applies to already-deployed CosmWasm contracts. Do not use native-denom pointers to build IBC or tokenfactory integrations. IBC is disabled in both directions, and tokenfactory is not a supported development path. Existing IBC balances may remain accessible through their pointers, but a pointer does not restore the route to the origin chain. For new tokens or NFTs, deploy ERC20 / ERC721 / ERC1155 contracts directly on the EVM. + Pointer Contracts enable tokens to be used interoperably in both EVM and Cosmos environments. Intended to be efficient and quick to deploy, a pointer diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index 0f5e545..58245f5 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -628,62 +628,6 @@ Metric names, units, and shape changed with the OpenTelemetry migration, so exis - The per-cache series that were previously separate metric names (for example `chunk_read_cache_*` and `chunk_write_cache_*`) are now the shared `litt_chunk_cache_*` metrics distinguished by the `cache` attribute. - The `MetricsNamespace` and `MetricsRegistry` config fields no longer exist. Metric names are fixed, and metrics are always backed by the global OTel provider; supply the scrape port via `MetricsPort`. -## IBC OpenTelemetry Metrics - -The IBC modules emit OpenTelemetry metrics through the process-wide `MeterProvider` (for example, a Prometheus exporter). These are emitted in parallel with the legacy `ibc_*` and `tx_msg_*` telemetry counters so you can migrate dashboards incrementally. The metrics are grouped by meter, one per IBC module. - -### Transfer Metrics (`ibc_transfer_keeper` meter) - -| Metric | Type | Description | -| --- | --- | --- | -| `ibc_transfer_tx_msg` | Gauge | Last amount of tokens transferred via IBC per denom class. | -| `ibc_transfer_packet_receive` | Gauge | Last amount of tokens received in an IBC packet per denom class. | -| `ibc_transfer_send` | Counter | Total number of IBC transfers sent. | -| `ibc_transfer_receive` | Counter | Total number of IBC transfers received. | - -The transfer gauges carry a `denom_class` attribute. `ibc_transfer_send` carries `destination_port`, `destination_channel`, and a boolean `source` attribute indicating whether the sending chain is the token source. `ibc_transfer_receive` carries `source_port`, `source_channel`, and the boolean `source` attribute. - -### Core Client Metrics (`ibc_core_client_keeper` meter) - -| Metric | Type | Description | -| --- | --- | --- | -| `ibc_client_create` | Counter | Total number of IBC client creates. | -| `ibc_client_update` | Counter | Total number of IBC client updates. | -| `ibc_client_upgrade` | Counter | Total number of IBC client upgrades. | -| `ibc_client_misbehaviour` | Counter | Total number of IBC client misbehaviour events. | - -These metrics carry a `client_type` attribute. `ibc_client_update`, `ibc_client_upgrade`, and `ibc_client_misbehaviour` also carry a `client_id` attribute. `ibc_client_update` additionally carries an `update_type` attribute (`msg` or `proposal`). `ibc_client_misbehaviour` also carries a `msg_type` attribute (value `update`) when the misbehaviour is detected during a client update. - -### Connection Metrics (`ibc_connection` meter) - -| Metric | Type | Description | -| --- | --- | --- | -| `ibc_connection_open_init` | Counter | Total number of IBC connection open-init handshakes. | -| `ibc_connection_open_try` | Counter | Total number of IBC connection open-try handshakes. | -| `ibc_connection_open_ack` | Counter | Total number of IBC connection open-ack handshakes. | -| `ibc_connection_open_confirm` | Counter | Total number of IBC connection open-confirm handshakes. | - -### Channel Metrics (`ibc_channel` meter) - -| Metric | Type | Description | -| --- | --- | --- | -| `ibc_channel_open_init` | Counter | Total number of IBC channel open-init handshakes. | -| `ibc_channel_open_try` | Counter | Total number of IBC channel open-try handshakes. | -| `ibc_channel_open_ack` | Counter | Total number of IBC channel open-ack handshakes. | -| `ibc_channel_open_confirm` | Counter | Total number of IBC channel open-confirm handshakes. | -| `ibc_channel_close_init` | Counter | Total number of IBC channel close-init handshakes. | -| `ibc_channel_close_confirm` | Counter | Total number of IBC channel close-confirm handshakes. | - -### Core Packet Metrics (`ibc_core` meter) - -| Metric | Type | Description | -| --- | --- | --- | -| `ibc_core_tx_msg_recv_packet` | Counter | Total number of IBC recv packet messages. | -| `ibc_core_timeout_packet` | Counter | Total number of IBC timeout packets. | -| `ibc_core_tx_msg_acknowledge_packet` | Counter | Total number of IBC acknowledge packet messages. | - -These packet metrics carry `source_port`, `source_channel`, `destination_port`, and `destination_channel` attributes. `ibc_core_timeout_packet` additionally carries a `timeout_type` attribute (`height` or `channel-closed`). - ## Performance Testing diff --git a/node/index.mdx b/node/index.mdx index 65a84d0..323bd87 100644 --- a/node/index.mdx +++ b/node/index.mdx @@ -10,7 +10,7 @@ import { RandomPeers } from '/snippets/random-peers.jsx'; **Power the Sei Network Infrastructure** -Comprehensive guides for running, maintaining, and optimizing Sei network nodes. Whether you're setting up a validator, an RPC node, or a relayer, you'll find detailed instructions and best practices to ensure optimal performance and security. +Comprehensive guides for running, maintaining, and optimizing Sei network nodes. Whether you're setting up a validator, an RPC node, or an archive node, you'll find detailed instructions and best practices to ensure optimal performance and security. diff --git a/scripts/generate-llms.mjs b/scripts/generate-llms.mjs index 91442cf..4f6f617 100644 --- a/scripts/generate-llms.mjs +++ b/scripts/generate-llms.mjs @@ -35,7 +35,8 @@ const SEI_LLMS_CONFIG = { 'Version compatibility: Solidity ≥ 0.8.x recommended. Sei EVM tracks the Pectra EVM (without blob transactions).', 'Network requirements: Mainnet chain ID 1329 (pacific-1), testnet chain ID 1328 (atlantic-2). Gas is paid in SEI (18 decimals).', 'Important notes: Sei has 400ms block times — set lower polling intervals than on Ethereum. Transactions touching independent state are parallelized automatically; shared-state writes are serialized.', - 'IBC disabled: Per SIP-03, IBC is disabled on Sei in both directions. Proposals 116 and 120 set the ibc module InboundEnabled parameter to false, and Proposal 121 set OutboundEnabled to false on 2026-07-31. No asset can be bridged into or out of Sei over IBC, and IBC assets already on Sei (USDC.n, USDT.kava, ATOM, WBTC) can no longer be redeemed on their origin chain. The IBC precompile at 0x0000000000000000000000000000000000001009 is non-functional. See /learn/sip-03-migration.' + 'IBC disabled: Per SIP-03, IBC is disabled on Sei in both directions. Proposals 116 and 120 set the ibc module InboundEnabled parameter to false, and Proposal 121 set OutboundEnabled to false on 2026-07-31. No asset can be bridged into or out of Sei over IBC, and IBC assets already on Sei (USDC.n, USDT.kava, ATOM, WBTC) can no longer be redeemed on their origin chain. The IBC precompile at 0x0000000000000000000000000000000000001009 is non-functional. See /learn/sip-03-migration.', + 'Tokenfactory unsupported: Do not recommend tokenfactory commands, APIs, Wasm bindings, native-denom pointer workflows, or other instructions for creating, minting, burning, administering, or integrating tokenfactory denoms. Legacy module surfaces may remain available for compatibility. Use ERC-20 for new fungible tokens. See /cosmos-sdk#tokenfactory-is-not-supported.' ].join('\n'), quickReference: [ 'Chain ID: mainnet 1329 (pacific-1), testnet 1328 (atlantic-2)', diff --git a/skill.md b/skill.md index db47492..adad35d 100644 --- a/skill.md +++ b/skill.md @@ -111,6 +111,8 @@ Once connected: address lookup, balance checks, transaction status, contract rea **The IBC precompile (`0x...1009`) is dead. Do not use or recommend it.** IBC is disabled on Sei in both directions (`ibc.InboundEnabled` and `ibc.OutboundEnabled` are both `false`, per governance Proposals 116, 120, and 121), so its `transfer` methods cannot succeed. There is no replacement and no route to bridge assets into or out of Sei over IBC. See the [SIP-03 Migration Guide](https://docs.sei.io/learn/sip-03-migration#ibc-is-disabled). +**Tokenfactory is not supported. Do not use or recommend it.** Do not provide commands, APIs, Wasm bindings, native-denom pointer workflows, or other instructions for creating, minting, burning, administering, or integrating tokenfactory denoms. Legacy module surfaces may still exist for compatibility. Use ERC-20 for new fungible tokens. See [Tokenfactory is not supported](https://docs.sei.io/cosmos-sdk#tokenfactory-is-not-supported). + ```ts import { STAKING_PRECOMPILE_ADDRESS,