본문으로 건너뛰기

Quick Start

5분 안에 GIWA SDK로 첫 번째 지갑을 생성해보세요.

1. Installation

# Expo
npx expo install giwa-react-native-wallet expo-secure-store

# React Native CLI
npm install giwa-react-native-wallet react-native-keychain
cd ios && pod install

2. Provider Setup

App.tsx
import { GiwaProvider } from 'giwa-react-native-wallet';

export default function App() {
return (
<GiwaProvider
network="testnet"
initTimeout={10000}
onError={(error) => console.error('SDK Error:', error)}
>
<WalletDemo />
</GiwaProvider>
);
}

GiwaProvider Props

Prop타입기본값설명
network'testnet' | 'mainnet''testnet'연결할 네트워크
config.endpointsCustomEndpoints-커스텀 RPC 및 탐색기 URL
config.customContractsCustomContracts-커스텀 컨트랙트 주소
initTimeoutnumber10000초기화 타임아웃 (ms)
onError(error: Error) => void-오류 발생 시 콜백

Custom Contract Addresses

SDK는 기본적으로 OP Stack 표준 사전배포 주소를 사용합니다. 필요시 재정의할 수 있습니다:

<GiwaProvider
config={{
network: 'testnet',
customContracts: {
eas: '0x...', // Custom EAS address
schemaRegistry: '0x...', // Custom Schema Registry
ensRegistry: '0x...', // Custom ENS Registry
},
}}
>
<App />
</GiwaProvider>

기본 주소는 Core API - 컨트랙트 주소를 참조하세요.

3. Create Wallet

WalletDemo.tsx
import { View, Text, Button, Alert } from 'react-native';
import { useGiwaWallet } from 'giwa-react-native-wallet';

export function WalletDemo() {
const { wallet, createWallet, isLoading } = useGiwaWallet();

const handleCreate = async () => {
try {
const { wallet, mnemonic } = await createWallet();

// Important: Guide user to safely backup their mnemonic
Alert.alert(
'Wallet Created',
`Address: ${wallet.address}\n\nPlease store your recovery phrase safely:\n${mnemonic}`
);
} catch (error) {
Alert.alert('Error', error.message);
}
};

if (isLoading) {
return <Text>Loading...</Text>;
}

return (
<View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
{wallet ? (
<>
<Text style={{ fontSize: 18, marginBottom: 10 }}>
Wallet Connected
</Text>
<Text selectable style={{ fontFamily: 'monospace' }}>
{wallet.address}
</Text>
</>
) : (
<Button title="Create New Wallet" onPress={handleCreate} />
)}
</View>
);
}

4. Check Balance

import { useBalance } from 'giwa-react-native-wallet';

function BalanceDisplay() {
const { formattedBalance, isLoading, refetch } = useBalance();

return (
<View>
<Text>Balance: {formattedBalance} ETH</Text>
<Button title="Refresh" onPress={refetch} disabled={isLoading} />
</View>
);
}

5. Send ETH

import { useState } from 'react';
import { useTransaction } from 'giwa-react-native-wallet';

function SendETH() {
const [to, setTo] = useState('');
const [amount, setAmount] = useState('');
const { sendTransaction, isLoading } = useTransaction();

const handleSend = async () => {
try {
const hash = await sendTransaction({ to, value: amount });
Alert.alert('Transfer Complete', `TX: ${hash}`);
} catch (error) {
Alert.alert('Error', error.message);
}
};

return (
<View>
<TextInput
placeholder="Recipient address (0x...)"
value={to}
onChangeText={setTo}
/>
<TextInput
placeholder="Amount (ETH)"
value={amount}
onChangeText={setAmount}
keyboardType="decimal-pad"
/>
<Button
title="Send"
onPress={handleSend}
disabled={isLoading || !to || !amount}
/>
</View>
);
}

6. Get Testnet ETH

import { useFaucet } from 'giwa-react-native-wallet';

function FaucetButton() {
const { requestFaucet, isLoading } = useFaucet();

const handleRequest = async () => {
try {
const result = await requestFaucet();
Alert.alert('Success', `Received ${result.amount} ETH`);
} catch (error) {
Alert.alert('Error', error.message);
}
};

return (
<Button
title="Get Testnet ETH"
onPress={handleRequest}
disabled={isLoading}
/>
);
}

Complete Example

App.tsx
import { useState } from 'react';
import { View, Text, Button, TextInput, Alert, StyleSheet } from 'react-native';
import {
GiwaProvider,
useGiwaWallet,
useBalance,
useTransaction,
useFaucet,
} from 'giwa-react-native-wallet';

function WalletApp() {
const { wallet, createWallet, isLoading: walletLoading } = useGiwaWallet();
const { formattedBalance, refetch } = useBalance();
const { sendTransaction, isLoading: txLoading } = useTransaction();
const { requestFaucet, isLoading: faucetLoading } = useFaucet();

const [to, setTo] = useState('');
const [amount, setAmount] = useState('');

if (!wallet) {
return (
<View style={styles.container}>
<Button
title="Create New Wallet"
onPress={createWallet}
disabled={walletLoading}
/>
</View>
);
}

return (
<View style={styles.container}>
<Text style={styles.address}>{wallet.address}</Text>
<Text style={styles.balance}>{formattedBalance} ETH</Text>

<Button title="Refresh Balance" onPress={refetch} />
<Button
title="Get Testnet ETH"
onPress={requestFaucet}
disabled={faucetLoading}
/>

<TextInput
style={styles.input}
placeholder="Recipient address"
value={to}
onChangeText={setTo}
/>
<TextInput
style={styles.input}
placeholder="Amount (ETH)"
value={amount}
onChangeText={setAmount}
keyboardType="decimal-pad"
/>
<Button
title="Send"
onPress={() => sendTransaction({ to, value: amount })}
disabled={txLoading}
/>
</View>
);
}

export default function App() {
return (
<GiwaProvider
network="testnet"
onError={(err) => console.error('SDK Error:', err)}
>
<WalletApp />
</GiwaProvider>
);
}

const styles = StyleSheet.create({
container: { flex: 1, padding: 20, justifyContent: 'center' },
address: { fontFamily: 'monospace', fontSize: 12, marginBottom: 10 },
balance: { fontSize: 24, fontWeight: 'bold', marginBottom: 20 },
input: { borderWidth: 1, borderColor: '#ccc', padding: 10, marginVertical: 5 },
});

Next Steps