chore: sync submodule state (parent ref update)
Made-with: Cursor
This commit is contained in:
52
examples/smart-accounts-react-example/README.md
Normal file
52
examples/smart-accounts-react-example/README.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Smart Accounts React Example
|
||||
|
||||
Complete React example demonstrating Smart Accounts Kit integration on ChainID 138.
|
||||
|
||||
## Features
|
||||
|
||||
- Connect to MetaMask
|
||||
- Create Smart Accounts
|
||||
- Request Delegations
|
||||
- View Delegation Status
|
||||
- Batch Operations (coming soon)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Update `src/App.tsx` to use your configuration:
|
||||
|
||||
```typescript
|
||||
const config = require('../../config/smart-accounts-config.json');
|
||||
```
|
||||
|
||||
Or create a local config file with your deployed contract addresses.
|
||||
|
||||
## Running
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
The app will open at `http://localhost:3000`.
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Connect Wallet**: Click "Connect MetaMask" to connect your wallet
|
||||
2. **Create Smart Account**: Click "Create Smart Account" to create a new Smart Account
|
||||
3. **Request Delegation**: Request delegation for a dApp or service
|
||||
4. **View Status**: View delegation status and expiry
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Developer Guide](../../docs/SMART_ACCOUNTS_API_REFERENCE.md)
|
||||
- [API Reference](../../docs/SMART_ACCOUNTS_API_REFERENCE.md)
|
||||
- [Delegation Guide](../../docs/SMART_ACCOUNTS_FAQ.md)
|
||||
|
||||
## License
|
||||
|
||||
See parent repository for license information.
|
||||
36
examples/smart-accounts-react-example/package.json
Normal file
36
examples/smart-accounts-react-example/package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "smart-accounts-react-example",
|
||||
"version": "1.0.0",
|
||||
"description": "React example for Smart Accounts Kit on ChainID 138",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@metamask/smart-accounts-kit": "^0.3.0",
|
||||
"ethers": "^6.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-scripts": "5.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
93
examples/smart-accounts-react-example/src/App.css
Normal file
93
examples/smart-accounts-react-example/src/App.css
Normal file
@@ -0,0 +1,93 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
padding: 20px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-main {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.section {
|
||||
background: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
margin-top: 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.section p {
|
||||
margin: 10px 0;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #4CAF50;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 10px 0;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
button:hover:not(:disabled) {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
background-color: #cccccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.App-footer {
|
||||
background-color: #282c34;
|
||||
padding: 20px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-footer a {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
background: white;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
border-radius: 4px;
|
||||
text-align: left;
|
||||
}
|
||||
220
examples/smart-accounts-react-example/src/App.tsx
Normal file
220
examples/smart-accounts-react-example/src/App.tsx
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Smart Accounts React Example
|
||||
*
|
||||
* Complete React example demonstrating Smart Accounts Kit integration
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { SmartAccountsKit } from '@metamask/smart-accounts-kit';
|
||||
import { ethers } from 'ethers';
|
||||
import './App.css';
|
||||
|
||||
// Load configuration
|
||||
const config = require('../../config/smart-accounts-config.json');
|
||||
|
||||
interface SmartAccount {
|
||||
address: string;
|
||||
owner: string;
|
||||
}
|
||||
|
||||
interface Delegation {
|
||||
target: string;
|
||||
active: boolean;
|
||||
expiry: number;
|
||||
permissions: string[];
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
|
||||
const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
|
||||
const [userAddress, setUserAddress] = useState<string>('');
|
||||
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
|
||||
const [smartAccountsKit, setSmartAccountsKit] = useState<SmartAccountsKit | null>(null);
|
||||
const [delegations, setDelegations] = useState<Delegation[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// Initialize MetaMask connection
|
||||
useEffect(() => {
|
||||
if (window.ethereum) {
|
||||
const initProvider = new ethers.BrowserProvider(window.ethereum);
|
||||
setProvider(initProvider);
|
||||
|
||||
// Initialize Smart Accounts Kit
|
||||
const kit = new SmartAccountsKit({
|
||||
chainId: config.chainId,
|
||||
rpcUrl: config.rpcUrl,
|
||||
entryPointAddress: config.entryPointAddress,
|
||||
accountFactoryAddress: config.accountFactoryAddress,
|
||||
paymasterAddress: config.paymasterAddress || undefined,
|
||||
});
|
||||
setSmartAccountsKit(kit);
|
||||
} else {
|
||||
setError('MetaMask is not installed');
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Connect to MetaMask
|
||||
const connectWallet = async () => {
|
||||
if (!provider) return;
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const accounts = await provider.send('eth_requestAccounts', []);
|
||||
const signer = await provider.getSigner();
|
||||
const address = await signer.getAddress();
|
||||
|
||||
setSigner(signer);
|
||||
setUserAddress(address);
|
||||
} catch (err: any) {
|
||||
setError(err.message || 'Failed to connect wallet');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Create Smart Account
|
||||
const createSmartAccount = async () => {
|
||||
if (!smartAccountsKit || !userAddress) return;
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const account = await smartAccountsKit.createAccount({
|
||||
owner: userAddress,
|
||||
});
|
||||
|
||||
setSmartAccount({
|
||||
address: account.address,
|
||||
owner: userAddress,
|
||||
});
|
||||
} catch (err: any) {
|
||||
setError(err.message || 'Failed to create smart account');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Request Delegation
|
||||
const requestDelegation = async (target: string) => {
|
||||
if (!smartAccountsKit || !smartAccount) return;
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const delegation = await smartAccountsKit.requestDelegation({
|
||||
target: target,
|
||||
permissions: ['execute_transactions', 'batch_operations'],
|
||||
expiry: Date.now() + 86400000, // 24 hours
|
||||
});
|
||||
|
||||
if (delegation.approved) {
|
||||
// Refresh delegations
|
||||
await loadDelegations();
|
||||
}
|
||||
} catch (err: any) {
|
||||
setError(err.message || 'Failed to request delegation');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Load Delegations
|
||||
const loadDelegations = async () => {
|
||||
if (!smartAccountsKit || !smartAccount) return;
|
||||
|
||||
try {
|
||||
// This would typically fetch from your backend or contract
|
||||
// For demo purposes, we'll use a placeholder
|
||||
const status = await smartAccountsKit.getDelegationStatus({
|
||||
target: '0x...', // Replace with actual target
|
||||
account: smartAccount.address,
|
||||
});
|
||||
|
||||
// Update delegations state
|
||||
// Implementation depends on your delegation storage
|
||||
} catch (err: any) {
|
||||
console.error('Failed to load delegations:', err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<h1>Smart Accounts Example</h1>
|
||||
<p>ChainID 138 - SMOM-DBIS-138</p>
|
||||
</header>
|
||||
|
||||
<main className="App-main">
|
||||
{error && (
|
||||
<div className="error">
|
||||
<strong>Error:</strong> {error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!userAddress ? (
|
||||
<div className="section">
|
||||
<h2>Connect Wallet</h2>
|
||||
<button onClick={connectWallet} disabled={loading || !provider}>
|
||||
{loading ? 'Connecting...' : 'Connect MetaMask'}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="section">
|
||||
<h2>Wallet Connected</h2>
|
||||
<p><strong>Address:</strong> {userAddress}</p>
|
||||
</div>
|
||||
|
||||
{!smartAccount ? (
|
||||
<div className="section">
|
||||
<h2>Create Smart Account</h2>
|
||||
<button onClick={createSmartAccount} disabled={loading}>
|
||||
{loading ? 'Creating...' : 'Create Smart Account'}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="section">
|
||||
<h2>Smart Account</h2>
|
||||
<p><strong>Address:</strong> {smartAccount.address}</p>
|
||||
<p><strong>Owner:</strong> {smartAccount.owner}</p>
|
||||
</div>
|
||||
|
||||
<div className="section">
|
||||
<h2>Delegations</h2>
|
||||
<button onClick={() => requestDelegation('0x...')} disabled={loading}>
|
||||
{loading ? 'Requesting...' : 'Request Delegation'}
|
||||
</button>
|
||||
{delegations.length > 0 && (
|
||||
<ul>
|
||||
{delegations.map((delegation, index) => (
|
||||
<li key={index}>
|
||||
<strong>Target:</strong> {delegation.target}<br />
|
||||
<strong>Active:</strong> {delegation.active ? 'Yes' : 'No'}<br />
|
||||
<strong>Expires:</strong> {new Date(delegation.expiry).toLocaleString()}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
|
||||
<footer className="App-footer">
|
||||
<p>
|
||||
See <a href="../../docs/SMART_ACCOUNTS_DEVELOPER_GUIDE.md">Developer Guide</a> for more information.
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
Reference in New Issue
Block a user