mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-22 18:17:58 +00:00
83b92fffde
PHASE 1 - Feature 1: DEX/Swap (COMPLETED ✅) ## New Components (5 files - 550 lines): 1. TokenIcon.tsx - Token emoji icons component 2. AddressDisplay.tsx - Formatted address display with copy functionality 3. BalanceCard.tsx - Token balance card with change indicators 4. TokenSelector.tsx - Modal token selector with search 5. Updated components/index.ts - Export new components ## New Screen: SwapScreen.tsx (800 lines) - Full-featured DEX swap interface ## Features Implemented: ✅ Real-time blockchain integration via Polkadot.js ✅ Live balance fetching for all tokens (HEZ, wHEZ, PEZ, wUSDT) ✅ Pool reserve queries from assetConversion pallet ✅ Automatic price calculations using shared DEX utilities ✅ Price impact calculation and display ✅ Slippage tolerance settings (0.5% to 50%) ✅ Minimum received amount calculation ✅ Transaction fee display (0.3%) ✅ Transaction signing and sending ✅ Success/error handling with user-friendly messages ✅ Loading states throughout ✅ Token balance display for all available tokens ✅ Swap token positions functionality ✅ Settings modal for slippage configuration ✅ Preset slippage buttons (0.5%, 1%, 2%, 5%) ## Blockchain Integration: - Uses shared/utils/dex.ts utilities (formatTokenBalance, parseTokenInput, calculatePriceImpact, getAmountOut, calculateMinAmount) - Real-time pool reserve fetching from chain - Transaction execution via assetConversion.swapTokensForExactTokens - Proper error extraction from dispatchError - Event monitoring for transaction finalization ## UI/UX: - Kurdistan color palette (green, red, yellow) - Price impact color coding (green<1%, yellow 1-3%, red>3%) - Disabled states for invalid inputs - Modal-based settings interface - Responsive layout with ScrollView - Proper keyboard handling (keyboardShouldPersistTaps) ## Navigation: - Added Swap tab to BottomTabNavigator - Swap icon: 🔄 (focused) / ↔️ (unfocused) - Positioned between Wallet and BeCitizen tabs ## Security: - Keypair loaded from secure storage - No private keys in state - Proper transaction validation - Slippage protection ## Dependencies: - Uses existing Polkadot.js API (16.5.2) - No new dependencies added - Fully compatible with existing infrastructure ## Testing Checklist: - [ ] Test on iOS simulator - [ ] Test on Android emulator - [ ] Test with real blockchain (beta testnet) - [ ] Test swap HEZ → PEZ - [ ] Test swap PEZ → wUSDT - [ ] Test slippage settings - [ ] Test error handling (insufficient balance) - [ ] Test loading states - [ ] Test token selector ## Next Steps: - Implement P2P Fiat Trading (Phase 1, Feature 2) - Add transaction history for swaps - Implement swap analytics Estimated completion: +10% (50% → 60%)
95 lines
2.0 KiB
TypeScript
95 lines
2.0 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
TouchableOpacity,
|
|
StyleSheet,
|
|
Clipboard,
|
|
} from 'react-native';
|
|
import { KurdistanColors } from '../theme/colors';
|
|
|
|
interface AddressDisplayProps {
|
|
address: string;
|
|
label?: string;
|
|
copyable?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Format address for display (e.g., "5GrwV...xQjz")
|
|
*/
|
|
const formatAddress = (address: string): string => {
|
|
if (!address) return '';
|
|
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
};
|
|
|
|
export const AddressDisplay: React.FC<AddressDisplayProps> = ({
|
|
address,
|
|
label,
|
|
copyable = true,
|
|
}) => {
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
const handleCopy = () => {
|
|
if (!copyable) return;
|
|
|
|
Clipboard.setString(address);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
};
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
{label && <Text style={styles.label}>{label}</Text>}
|
|
<TouchableOpacity
|
|
onPress={handleCopy}
|
|
disabled={!copyable}
|
|
activeOpacity={0.7}
|
|
>
|
|
<View style={styles.addressContainer}>
|
|
<Text style={styles.address}>{formatAddress(address)}</Text>
|
|
{copyable && (
|
|
<Text style={styles.copyIcon}>{copied ? '✅' : '📋'}</Text>
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
{copied && <Text style={styles.copiedText}>Copied!</Text>}
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
marginVertical: 4,
|
|
},
|
|
label: {
|
|
fontSize: 12,
|
|
color: '#666',
|
|
marginBottom: 4,
|
|
},
|
|
addressContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
padding: 8,
|
|
backgroundColor: '#F5F5F5',
|
|
borderRadius: 8,
|
|
borderWidth: 1,
|
|
borderColor: '#E0E0E0',
|
|
},
|
|
address: {
|
|
flex: 1,
|
|
fontSize: 14,
|
|
fontFamily: 'monospace',
|
|
color: '#000',
|
|
},
|
|
copyIcon: {
|
|
fontSize: 18,
|
|
marginLeft: 8,
|
|
},
|
|
copiedText: {
|
|
fontSize: 12,
|
|
color: KurdistanColors.kesk,
|
|
marginTop: 4,
|
|
textAlign: 'center',
|
|
},
|
|
});
|