Add initial project structure and documentation files

- Created .gitignore to exclude sensitive files and directories.
- Added API documentation in API_DOCUMENTATION.md.
- Included deployment instructions in DEPLOYMENT.md.
- Established project structure documentation in PROJECT_STRUCTURE.md.
- Updated README.md with project status and team information.
- Added recommendations and status tracking documents.
- Introduced testing guidelines in TESTING.md.
- Set up CI workflow in .github/workflows/ci.yml.
- Created Dockerfile for backend and frontend setups.
- Added various service and utility files for backend functionality.
- Implemented frontend components and pages for user interface.
- Included mobile app structure and services.
- Established scripts for deployment across multiple chains.
This commit is contained in:
defiQUG
2025-12-03 21:22:31 -08:00
commit 507d9a35b1
261 changed files with 47004 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
import ReactNativeBiometrics from 'react-native-biometrics';
export class BiometricService {
private static rnBiometrics = new ReactNativeBiometrics();
static async isAvailable(): Promise<boolean> {
try {
const { available } = await this.rnBiometrics.isSensorAvailable();
return available;
} catch (error) {
return false;
}
}
static async authenticate(reason: string = 'Authenticate to access ASLE'): Promise<boolean> {
try {
const { success } = await this.rnBiometrics.simplePrompt({
promptMessage: reason,
});
return success;
} catch (error) {
return false;
}
}
static async createKeys(): Promise<{ publicKey: string; privateKey: string } | null> {
try {
const { publicKey } = await this.rnBiometrics.createKeys();
return { publicKey, privateKey: '' }; // Private key is stored securely
} catch (error) {
return null;
}
}
}

View File

@@ -0,0 +1,86 @@
import { Linking } from 'react-native';
export interface DeepLink {
type: 'transaction' | 'proposal' | 'pool' | 'vault';
id: string;
params?: Record<string, string>;
}
export class DeepLinkingService {
/**
* Parse deep link URL
*/
static parseUrl(url: string): DeepLink | null {
try {
const parsed = new URL(url);
const path = parsed.pathname;
if (path.startsWith('/transaction/')) {
return {
type: 'transaction',
id: path.split('/transaction/')[1],
};
} else if (path.startsWith('/proposal/')) {
return {
type: 'proposal',
id: path.split('/proposal/')[1],
};
} else if (path.startsWith('/pool/')) {
return {
type: 'pool',
id: path.split('/pool/')[1],
};
} else if (path.startsWith('/vault/')) {
return {
type: 'vault',
id: path.split('/vault/')[1],
};
}
return null;
} catch (error) {
return null;
}
}
/**
* Handle incoming deep link
*/
static async handleDeepLink(url: string, navigation: any): Promise<void> {
const link = this.parseUrl(url);
if (!link) return;
switch (link.type) {
case 'transaction':
// Navigate to transaction details
break;
case 'proposal':
navigation.navigate('ProposalDetails', { proposalId: link.id });
break;
case 'pool':
navigation.navigate('PoolDetails', { poolId: link.id });
break;
case 'vault':
navigation.navigate('VaultDetails', { vaultId: link.id });
break;
}
}
/**
* Initialize deep linking listener
*/
static initialize(navigation: any) {
// Handle initial URL
Linking.getInitialURL().then((url) => {
if (url) {
this.handleDeepLink(url, navigation);
}
});
// Handle URL changes
Linking.addEventListener('url', (event) => {
this.handleDeepLink(event.url, navigation);
});
}
}

View File

@@ -0,0 +1,52 @@
import PushNotification from 'react-native-push-notification';
export class NotificationService {
static initialize() {
PushNotification.configure({
onRegister: function (token) {
console.log('TOKEN:', token);
},
onNotification: function (notification) {
console.log('NOTIFICATION:', notification);
},
permissions: {
alert: true,
badge: true,
sound: true,
},
popInitialNotification: true,
requestPermissions: true,
});
PushNotification.createChannel(
{
channelId: 'asle-default',
channelName: 'ASLE Notifications',
channelDescription: 'Notifications for ASLE platform',
playSound: true,
soundName: 'default',
importance: 4,
vibrate: true,
},
(created) => console.log(`Channel created: ${created}`)
);
}
static scheduleLocalNotification(title: string, message: string, date: Date) {
PushNotification.localNotificationSchedule({
channelId: 'asle-default',
title,
message,
date,
});
}
static sendLocalNotification(title: string, message: string) {
PushNotification.localNotification({
channelId: 'asle-default',
title,
message,
});
}
}

View File

@@ -0,0 +1,74 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
export class OfflineService {
private static CACHE_PREFIX = 'asle_cache_';
private static QUEUE_KEY = 'asle_transaction_queue';
/**
* Cache data for offline access
*/
static async cacheData(key: string, data: any): Promise<void> {
try {
await AsyncStorage.setItem(
`${this.CACHE_PREFIX}${key}`,
JSON.stringify({ data, timestamp: Date.now() })
);
} catch (error) {
console.error('Error caching data:', error);
}
}
/**
* Get cached data
*/
static async getCachedData(key: string): Promise<any | null> {
try {
const cached = await AsyncStorage.getItem(`${this.CACHE_PREFIX}${key}`);
if (!cached) return null;
const { data, timestamp } = JSON.parse(cached);
// Check if cache is still valid (24 hours)
if (Date.now() - timestamp > 24 * 60 * 60 * 1000) {
await AsyncStorage.removeItem(`${this.CACHE_PREFIX}${key}`);
return null;
}
return data;
} catch (error) {
return null;
}
}
/**
* Queue transaction for when online
*/
static async queueTransaction(transaction: any): Promise<void> {
try {
const queue = await this.getTransactionQueue();
queue.push({ ...transaction, queuedAt: Date.now() });
await AsyncStorage.setItem(this.QUEUE_KEY, JSON.stringify(queue));
} catch (error) {
console.error('Error queueing transaction:', error);
}
}
/**
* Get transaction queue
*/
static async getTransactionQueue(): Promise<any[]> {
try {
const queue = await AsyncStorage.getItem(this.QUEUE_KEY);
return queue ? JSON.parse(queue) : [];
} catch (error) {
return [];
}
}
/**
* Clear transaction queue
*/
static async clearTransactionQueue(): Promise<void> {
await AsyncStorage.removeItem(this.QUEUE_KEY);
}
}

View File

@@ -0,0 +1,67 @@
import { createConfig, http } from '@wagmi/core';
import { mainnet, polygon, arbitrum, optimism, bsc, avalanche, base } from '@wagmi/core/chains';
import { injected, metaMask } from '@wagmi/core/connectors';
export const wagmiConfig = createConfig({
chains: [mainnet, polygon, arbitrum, optimism, bsc, avalanche, base],
connectors: [injected(), metaMask()],
transports: {
[mainnet.id]: http(),
[polygon.id]: http(),
[arbitrum.id]: http(),
[optimism.id]: http(),
[bsc.id]: http(),
[avalanche.id]: http(),
[base.id]: http(),
},
});
export interface WalletState {
address: string | null;
chainId: number | null;
connected: boolean;
}
export class WalletService {
private static instance: WalletService;
private state: WalletState = {
address: null,
chainId: null,
connected: false,
};
static getInstance(): WalletService {
if (!WalletService.instance) {
WalletService.instance = new WalletService();
}
return WalletService.instance;
}
async connect(): Promise<WalletState> {
// In production, this would use WalletConnect or similar
// For now, return mock state
this.state = {
address: '0x1234567890123456789012345678901234567890',
chainId: 1,
connected: true,
};
return this.state;
}
async disconnect(): Promise<void> {
this.state = {
address: null,
chainId: null,
connected: false,
};
}
getState(): WalletState {
return this.state;
}
async switchChain(chainId: number): Promise<void> {
this.state.chainId = chainId;
}
}