Add Oracle Aggregator and CCIP Integration
- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
This commit is contained in:
309
docs/operations/integrations/METAMASK_DEVELOPER_GUIDE.md
Normal file
309
docs/operations/integrations/METAMASK_DEVELOPER_GUIDE.md
Normal file
@@ -0,0 +1,309 @@
|
||||
# MetaMask Developer Guide for ChainID 138
|
||||
|
||||
Developer guide for integrating ChainID 138 with MetaMask in your dapp.
|
||||
|
||||
## Installation
|
||||
|
||||
### Using npm
|
||||
|
||||
```bash
|
||||
npm install @defi-oracle/metamask-sdk
|
||||
```
|
||||
|
||||
### Using the source
|
||||
|
||||
```bash
|
||||
cd metamask-sdk
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Import the SDK
|
||||
|
||||
```typescript
|
||||
import {
|
||||
addOrSwitchNetwork,
|
||||
addToken,
|
||||
isOnChain138,
|
||||
getCurrentChainId,
|
||||
} from '@defi-oracle/metamask-sdk';
|
||||
```
|
||||
|
||||
### Connect to ChainID 138
|
||||
|
||||
```typescript
|
||||
async function connect() {
|
||||
try {
|
||||
await addOrSwitchNetwork();
|
||||
const isOn138 = await isOnChain138();
|
||||
if (isOn138) {
|
||||
console.log('Connected to ChainID 138');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Connection error:', error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Add Token
|
||||
|
||||
```typescript
|
||||
async function addWETHToken() {
|
||||
try {
|
||||
await addToken(
|
||||
'0xYourWETHAddress',
|
||||
'WETH',
|
||||
18,
|
||||
'https://explorer.d-bis.org/images/tokens/weth.png'
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Token add error:', error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## React Integration
|
||||
|
||||
### Custom Hook
|
||||
|
||||
```typescript
|
||||
import { useState, useEffect } from 'react';
|
||||
import { isOnChain138, addOrSwitchNetwork } from '@defi-oracle/metamask-sdk';
|
||||
|
||||
function useChain138() {
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
checkConnection();
|
||||
|
||||
// Listen for chain changes
|
||||
if (window.ethereum) {
|
||||
window.ethereum.on('chainChanged', checkConnection);
|
||||
return () => {
|
||||
window.ethereum.removeListener('chainChanged', checkConnection);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
async function checkConnection() {
|
||||
try {
|
||||
const on138 = await isOnChain138();
|
||||
setIsConnected(on138);
|
||||
} catch (error) {
|
||||
setIsConnected(false);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function connect() {
|
||||
try {
|
||||
await addOrSwitchNetwork();
|
||||
await checkConnection();
|
||||
} catch (error) {
|
||||
console.error('Connection error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
return { isConnected, isLoading, connect };
|
||||
}
|
||||
```
|
||||
|
||||
### React Component
|
||||
|
||||
```typescript
|
||||
import React from 'react';
|
||||
import { useChain138 } from './useChain138';
|
||||
|
||||
function Chain138Button() {
|
||||
const { isConnected, isLoading, connect } = useChain138();
|
||||
|
||||
if (isLoading) {
|
||||
return <button disabled>Loading...</button>;
|
||||
}
|
||||
|
||||
if (isConnected) {
|
||||
return <button disabled>Connected to ChainID 138</button>;
|
||||
}
|
||||
|
||||
return (
|
||||
<button onClick={connect}>
|
||||
Connect to ChainID 138
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Vue Integration
|
||||
|
||||
### Composable
|
||||
|
||||
```typescript
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { isOnChain138, addOrSwitchNetwork } from '@defi-oracle/metamask-sdk';
|
||||
|
||||
export function useChain138() {
|
||||
const isConnected = ref(false);
|
||||
const isLoading = ref(true);
|
||||
|
||||
async function checkConnection() {
|
||||
try {
|
||||
const on138 = await isOnChain138();
|
||||
isConnected.value = on138;
|
||||
} catch (error) {
|
||||
isConnected.value = false;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function connect() {
|
||||
try {
|
||||
await addOrSwitchNetwork();
|
||||
await checkConnection();
|
||||
} catch (error) {
|
||||
console.error('Connection error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function handleChainChanged() {
|
||||
checkConnection();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkConnection();
|
||||
if (window.ethereum) {
|
||||
window.ethereum.on('chainChanged', handleChainChanged);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (window.ethereum) {
|
||||
window.ethereum.removeListener('chainChanged', handleChainChanged);
|
||||
}
|
||||
});
|
||||
|
||||
return { isConnected, isLoading, connect };
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
```typescript
|
||||
import { addNetwork } from '@defi-oracle/metamask-sdk';
|
||||
|
||||
try {
|
||||
await addNetwork();
|
||||
} catch (error) {
|
||||
if (error.message.includes('MetaMask is not installed')) {
|
||||
// Handle MetaMask not installed
|
||||
alert('Please install MetaMask');
|
||||
} else if (error.message.includes('User rejected')) {
|
||||
// Handle user rejection
|
||||
console.log('User rejected the request');
|
||||
} else if (error.code === 4902) {
|
||||
// Network already added, try switching
|
||||
await switchNetwork();
|
||||
} else {
|
||||
// Handle other errors
|
||||
console.error('Unexpected error:', error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## RPC Best Practices
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
- Default: 1200 requests/minute per IP
|
||||
- Use request batching when possible
|
||||
- Implement client-side rate limiting
|
||||
- Use WebSocket connections for real-time data
|
||||
|
||||
### Request Batching
|
||||
|
||||
```typescript
|
||||
const batch = [
|
||||
{ method: 'eth_blockNumber', params: [] },
|
||||
{ method: 'eth_gasPrice', params: [] },
|
||||
{ method: 'eth_getBalance', params: [address, 'latest'] },
|
||||
];
|
||||
|
||||
const results = await Promise.all(
|
||||
batch.map(req => window.ethereum.request(req))
|
||||
);
|
||||
```
|
||||
|
||||
### WebSocket Connections
|
||||
|
||||
```typescript
|
||||
const ws = new WebSocket('wss://rpc.d-bis.org');
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('Received:', data);
|
||||
};
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
method: 'eth_subscribe',
|
||||
params: ['newHeads'],
|
||||
id: 1
|
||||
}));
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Mock MetaMask for Testing
|
||||
|
||||
```typescript
|
||||
// mock-metamask.ts
|
||||
export function createMockMetaMask() {
|
||||
return {
|
||||
isMetaMask: true,
|
||||
request: async (args: { method: string; params?: unknown[] }) => {
|
||||
if (args.method === 'eth_chainId') {
|
||||
return '0x8a';
|
||||
}
|
||||
if (args.method === 'wallet_addEthereumChain') {
|
||||
return null;
|
||||
}
|
||||
if (args.method === 'wallet_switchEthereumChain') {
|
||||
return null;
|
||||
}
|
||||
throw new Error('Method not implemented');
|
||||
},
|
||||
on: () => {},
|
||||
removeListener: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
// In your tests
|
||||
global.window.ethereum = createMockMetaMask();
|
||||
```
|
||||
|
||||
## Production Checklist
|
||||
|
||||
- [ ] Verify RPC URLs are correct and accessible
|
||||
- [ ] Test network addition on all target browsers
|
||||
- [ ] Test token addition for all tokens
|
||||
- [ ] Verify error handling for all error cases
|
||||
- [ ] Test network switching functionality
|
||||
- [ ] Verify chain change event listeners
|
||||
- [ ] Test on mobile MetaMask
|
||||
- [ ] Verify token logos are accessible
|
||||
- [ ] Test with different MetaMask versions
|
||||
- [ ] Verify CORS headers on RPC endpoints
|
||||
|
||||
## References
|
||||
|
||||
- [MetaMask SDK Documentation](../metamask-sdk/README.md)
|
||||
- [MetaMask Integration Guide](./METAMASK_INTEGRATION.md)
|
||||
- [Quick Start Guide](../metamask/QUICK_START.md)
|
||||
- [MetaMask Documentation](https://docs.metamask.io)
|
||||
|
||||
Reference in New Issue
Block a user