chore: sync submodule state (parent ref update)

Made-with: Cursor
This commit is contained in:
defiQUG
2026-03-02 12:14:14 -08:00
parent b6a776e5d7
commit 25c96e210a
316 changed files with 29779 additions and 677 deletions

View File

@@ -0,0 +1,58 @@
# MetaMask ChainID 138 React Example
Complete React example for integrating MetaMask with ChainID 138.
## Features
- ✅ Connect to MetaMask wallet
- ✅ Add ChainID 138 network
- ✅ Switch to ChainID 138 network
- ✅ Add tokens (cUSDT, cUSDC, WETH)
- ✅ Display wallet balance
- ✅ Error handling
## Installation
```bash
npm install
```
## Development
```bash
npm run dev
```
## Build
```bash
npm run build
```
## Usage
1. Install MetaMask browser extension
2. Open the application
3. Click "Connect Wallet"
4. Approve connection in MetaMask
5. Add ChainID 138 network if needed
6. Add tokens to MetaMask
## Code Structure
- `App.tsx` - Main component with wallet connection logic
- `App.css` - Styling
- Uses `ethers.js` v6 for blockchain interactions
## Network Configuration
The example includes ChainID 138 network configuration:
- Chain ID: 138 (0x8a)
- RPC URLs: https://rpc.d-bis.org, https://rpc2.d-bis.org
- Explorer: https://explorer.d-bis.org
## Token Addresses
- cUSDT: `0x93E66202A11B1772E55407B32B44e5Cd8eda7f22` (6 decimals)
- cUSDC: `0xf22258f57794CC8E06237084b353Ab30fFfa640b` (6 decimals)
- WETH: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` (18 decimals)

View File

@@ -0,0 +1,23 @@
{
"name": "metamask-chain138-react-example",
"version": "1.0.0",
"description": "React example for MetaMask integration with ChainID 138",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ethers": "^6.9.0"
},
"devDependencies": {
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@vitejs/plugin-react": "^4.2.0",
"typescript": "^5.2.0",
"vite": "^5.0.0"
}
}

View File

@@ -0,0 +1,97 @@
.app {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
padding: 40px;
max-width: 600px;
width: 100%;
}
h1 {
color: #333;
margin-bottom: 20px;
font-size: 28px;
}
h2 {
color: #333;
margin-bottom: 15px;
font-size: 22px;
}
h3 {
color: #555;
margin-bottom: 10px;
font-size: 18px;
}
.wallet-info {
margin-top: 20px;
}
.wallet-info p {
margin: 10px 0;
color: #666;
}
.network-section,
.tokens-section {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #eee;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
margin: 5px;
}
.btn-primary {
background: #667eea;
color: white;
}
.btn-primary:hover {
background: #5568d3;
}
.btn-secondary {
background: #48bb78;
color: white;
}
.btn-secondary:hover {
background: #38a169;
}
.btn-token {
background: #ed8936;
color: white;
}
.btn-token:hover {
background: #dd6b20;
}
.error {
background: #fed7d7;
color: #c53030;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}

View File

@@ -0,0 +1,208 @@
import { useState, useEffect } from 'react';
import { ethers } from 'ethers';
import './App.css';
// ChainID 138 Network Configuration
const CHAIN_138_CONFIG = {
chainId: '0x8a', // 138 in hex
chainName: 'DeFi Oracle Meta Mainnet',
nativeCurrency: {
name: 'Ether',
symbol: 'ETH',
decimals: 18,
},
rpcUrls: ['https://rpc.d-bis.org', 'https://rpc2.d-bis.org'],
blockExplorerUrls: ['https://explorer.d-bis.org'],
};
// Token addresses
const TOKENS = {
cUSDT: '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22',
cUSDC: '0xf22258f57794CC8E06237084b353Ab30fFfa640b',
WETH: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
};
function App() {
const [account, setAccount] = useState<string | null>(null);
const [chainId, setChainId] = useState<string | null>(null);
const [balance, setBalance] = useState<string>('0');
const [isConnected, setIsConnected] = useState(false);
const [error, setError] = useState<string | null>(null);
// Check if MetaMask is installed
const isMetaMaskInstalled = typeof window.ethereum !== 'undefined';
// Connect to MetaMask
const connectWallet = async () => {
if (!isMetaMaskInstalled) {
setError('MetaMask is not installed. Please install MetaMask extension.');
return;
}
try {
const provider = new ethers.BrowserProvider(window.ethereum);
const accounts = await provider.send('eth_requestAccounts', []);
if (accounts.length > 0) {
setAccount(accounts[0]);
setIsConnected(true);
setError(null);
// Get chain ID
const network = await provider.getNetwork();
setChainId(network.chainId.toString());
// Get balance
const balance = await provider.getBalance(accounts[0]);
setBalance(ethers.formatEther(balance));
}
} catch (err: any) {
setError(err.message || 'Failed to connect wallet');
}
};
// Add ChainID 138 to MetaMask
const addChain138 = async () => {
if (!isMetaMaskInstalled) {
setError('MetaMask is not installed');
return;
}
try {
await window.ethereum.request({
method: 'wallet_addEthereumChain',
params: [CHAIN_138_CONFIG],
});
setError(null);
} catch (err: any) {
setError(err.message || 'Failed to add network');
}
};
// Switch to ChainID 138
const switchToChain138 = async () => {
if (!isMetaMaskInstalled) {
setError('MetaMask is not installed');
return;
}
try {
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: CHAIN_138_CONFIG.chainId }],
});
setError(null);
// Refresh connection
const provider = new ethers.BrowserProvider(window.ethereum);
const network = await provider.getNetwork();
setChainId(network.chainId.toString());
} catch (err: any) {
// If chain is not added, try to add it
if ((err as any).code === 4902) {
await addChain138();
} else {
setError((err as any).message || 'Failed to switch network');
}
}
};
// Add token to MetaMask
const addToken = async (symbol: string, address: string, decimals: number) => {
if (!isMetaMaskInstalled) {
setError('MetaMask is not installed');
return;
}
try {
await window.ethereum.request({
method: 'wallet_watchAsset',
params: {
type: 'ERC20',
options: {
address: address,
symbol: symbol,
decimals: decimals,
},
},
});
setError(null);
} catch (err: any) {
setError(err.message || 'Failed to add token');
}
};
// Check if on ChainID 138
const isOnChain138 = chainId === '138';
return (
<div className="app">
<div className="container">
<h1>MetaMask ChainID 138 Example</h1>
{!isMetaMaskInstalled && (
<div className="error">
MetaMask is not installed. Please install MetaMask extension.
</div>
)}
{error && (
<div className="error">
{error}
</div>
)}
{!isConnected ? (
<button onClick={connectWallet} className="btn btn-primary">
Connect Wallet
</button>
) : (
<div className="wallet-info">
<h2>Wallet Connected</h2>
<p><strong>Account:</strong> {account}</p>
<p><strong>Chain ID:</strong> {chainId}</p>
<p><strong>Balance:</strong> {parseFloat(balance).toFixed(4)} ETH</p>
{!isOnChain138 && (
<div className="network-section">
<h3>Network Setup</h3>
<button onClick={addChain138} className="btn btn-secondary">
Add ChainID 138
</button>
<button onClick={switchToChain138} className="btn btn-secondary">
Switch to ChainID 138
</button>
</div>
)}
{isOnChain138 && (
<div className="tokens-section">
<h3>Add Tokens</h3>
<button
onClick={() => addToken('cUSDT', TOKENS.cUSDT, 6)}
className="btn btn-token"
>
Add cUSDT
</button>
<button
onClick={() => addToken('cUSDC', TOKENS.cUSDC, 6)}
className="btn btn-token"
>
Add cUSDC
</button>
<button
onClick={() => addToken('WETH', TOKENS.WETH, 18)}
className="btn btn-token"
>
Add WETH
</button>
</div>
)}
</div>
)}
</div>
</div>
);
}
export default App;