Описание изменений

This commit is contained in:
2025-02-19 12:36:38 +03:00
parent b56e6b5e46
commit 7cb967138d
20 changed files with 1886 additions and 297 deletions

View File

@@ -4,9 +4,7 @@
<div v-if="!isConnected" class="warning">
Пожалуйста, подключите кошелек для управления контрактом
<button @click="handleConnect" class="connect-button">
Подключить кошелек
</button>
<appkit-button />
</div>
<div v-else>
@@ -39,6 +37,7 @@
import { ref, onMounted, watch } from 'vue';
import { ethers } from 'ethers';
import { useAppKitAccount, useAppKitProvider, useAppKit } from '@reown/appkit/vue';
import config from '../config';
export default {
name: 'ContractInteraction',
@@ -48,17 +47,11 @@ export default {
const loading = ref(false);
const { address, isConnected } = useAppKitAccount();
const { walletProvider } = useAppKitProvider('eip155');
const appKit = useAppKit();
const { contractAddress, contractABI } = config.contract;
const contractAddress = '0x6199Ba629C85Da887dBd8Ffd8d2C75Ea24EaDe2a';
const contractABI = [
'function owner() view returns (address)',
'function setOwner(address newOwner)',
];
const { open } = useAppKit(); // Получаем функцию открытия модала
const formatAddress = (addr) => {
return addr.slice(0, 6) + '...' + addr.slice(-4);
};
const formatAddress = (addr) => addr.slice(0, 6) + '...' + addr.slice(-4);
const isValidAddress = (addr) => {
try {
@@ -68,14 +61,31 @@ export default {
}
};
// Добавим логирование для отладки
watch(() => isConnected, (newValue) => {
console.log('Состояние подключения изменилось:', newValue);
console.log('Адрес кошелька:', address);
}, { immediate: true });
// Следим за изменением состояния подключения
watch(isConnected, async (newValue) => {
console.log('Connection state changed:', newValue);
if (newValue) {
await fetchOwner();
} else {
owner.value = '';
}
});
const handleConnect = async () => {
try {
console.log('Attempting to connect wallet...');
await open(); // Используем хуки для открытия модала
console.log('Wallet connected successfully');
} catch (error) {
console.error('Wallet connection error:', error);
}
};
const fetchOwner = async () => {
if (!isConnected) return;
if (!isConnected.value || !walletProvider) {
console.log('Cannot fetch owner: wallet not connected');
return;
}
loading.value = true;
try {
console.log('Получаем владельца контракта...');
@@ -93,7 +103,7 @@ export default {
const setNewOwner = async () => {
try {
if (!isConnected) {
if (!isConnected.value) {
console.log('Пожалуйста, подключите кошелек');
return;
}
@@ -109,37 +119,17 @@ export default {
const tx = await contract.setOwner(newOwner.value);
await tx.wait();
// Обновляем информацию после успешной транзакции
await fetchOwner();
newOwner.value = ''; // Очищаем поле ввода
newOwner.value = '';
} catch (error) {
console.error('Ошибка при установке нового владельца:', error);
}
};
// Обработчик подключения кошелька
const handleConnect = async () => {
try {
await appKit.open();
} catch (error) {
console.error('Ошибка при подключении:', error);
onMounted(async () => {
if (isConnected.value) {
await fetchOwner();
}
};
// Обновляем watch
watch(() => isConnected, (newValue, oldValue) => {
console.log('Состояние подключения изменилось:', { newValue, oldValue });
if (newValue) {
fetchOwner();
} else {
owner.value = '';
}
}, { immediate: true });
onMounted(() => {
// Проверяем состояние подключения при монтировании
console.log('Компонент смонтирован, isConnected:', isConnected);
fetchOwner();
});
return {
@@ -148,7 +138,6 @@ export default {
isConnected,
loading,
handleConnect,
walletProvider,
setNewOwner,
formatAddress,
isValidAddress

View File

@@ -5,4 +5,32 @@ export const projectId = '9a6515f7259ebccd149fd53341e01e6b'
export const networks = [sepolia]
export const ethersAdapter = new EthersAdapter()
export const ethersAdapter = new EthersAdapter()
export const config = {
ethereum: {
networkUrl: import.meta.env.VITE_APP_ETHEREUM_NETWORK_URL as string,
projectId: import.meta.env.VITE_APP_PROJECT_ID as string
},
api: {
baseUrl: 'http://localhost:3000', // URL бэкенда
endpoints: {
verify: '/api/verify'
}
},
contract: {
address: '0x6199Ba629C85Da887dBd8Ffd8d2C75Ea24EaDe2a',
abi: [
'function owner() view returns (address)',
'function setOwner(address newOwner)'
]
},
metadata: {
name: 'DApp for Business',
description: 'Управление смарт-контрактом',
url: window.location.origin,
icons: ['https://avatars.githubusercontent.com/u/37784886']
}
};
export default config;

7
frontend/src/env.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

View File

@@ -3,103 +3,24 @@ import App from './App.vue';
import { createAppKit } from '@reown/appkit/vue';
import { EthersAdapter } from '@reown/appkit-adapter-ethers';
import { sepolia } from '@reown/appkit/networks';
import { createSIWEConfig, formatMessage } from '@reown/appkit-siwe';
import config from './config'; // Импортируем конфигурацию
// Определяем базовый URL для API
const BASE_URL = 'http://localhost:3000';
// 1. Get projectId
const projectId = '9a6515f7259ebccd149fd53341e01e6b';
// 2. Create SIWE config
const siweConfig = createSIWEConfig({
getMessageParams: async () => ({
domain: window.location.host,
uri: window.location.origin,
chains: [11155111], // Sepolia chainId
statement: 'Подпишите это сообщение для входа в DApp for Business. Это безопасно и не требует оплаты.',
}),
createMessage: ({ address, ...args }) => formatMessage(args, address),
getNonce: async () => {
try {
const res = await fetch(`${BASE_URL}/nonce`, {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'text/plain'
}
});
if (!res.ok) throw new Error('Failed to get nonce');
return await res.text();
} catch (error) {
console.error('Ошибка получения nonce:', error);
throw error;
}
const appKit = createAppKit({
adapters: [new EthersAdapter()],
projectId: config.ethereum.projectId,
networks: [sepolia],
defaultNetwork: sepolia,
metadata: config.metadata,
features: {
analytics: true
},
getSession: async () => {
try {
const res = await fetch(`${BASE_URL}/session`, {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'application/json'
}
});
if (!res.ok) return null;
return await res.json();
} catch (error) {
console.error('Ошибка получения сессии:', error);
return null;
}
},
verifyMessage: async ({ message, signature }) => {
try {
const res = await fetch(`${BASE_URL}/verify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({ message, signature }),
credentials: 'include'
});
return res.ok;
} catch (error) {
console.error('Ошибка верификации:', error);
return false;
}
},
signOut: async () => {
try {
await fetch(`${BASE_URL}/signout`, {
method: 'GET',
credentials: 'include'
});
} catch (error) {
console.error('Ошибка выхода:', error);
}
themeMode: 'light', // Добавляем светлую тему
themeVariables: {
'--w3m-color-mix': '#00BB7F',
'--w3m-color-mix-strength': 40
}
});
// 3. Create AppKit instance
createAppKit({
adapters: [new EthersAdapter()],
networks: [sepolia],
projectId,
metadata: {
name: 'DApp for Business',
description: 'Smart Contract Management DApp',
url: window.location.origin,
icons: ['https://avatars.githubusercontent.com/u/37784886']
},
defaultNetwork: sepolia,
features: {
analytics: true,
connectMethodsOrder: ['wallet', 'email', 'social'],
autoConnect: false
},
siweConfig
});
const app = createApp(App);
app.use(appKit); // Подключаем AppKit как плагин
app.mount('#app');

View File

@@ -0,0 +1,5 @@
export interface ContractState {
owner: string;
isConnected: boolean;
loading: boolean;
}

View File

@@ -0,0 +1,9 @@
import { ethers } from 'ethers';
export const formatAddress = (address: string): string => {
return `${address.slice(0, 6)}...${address.slice(-4)}`;
};
export const isValidAddress = (address: string): boolean => {
return ethers.isAddress(address);
};