Dojang (Attestations)
This guide explains the Dojang attestation service based on EAS (Ethereum Attestation Service).
Attestation Creation
Attestations can only be created by official issuers (e.g., Upbit Korea). This SDK provides read-only access for verifying attestations.
See: Dojang Documentation
What is Dojang?
Dojang is GIWA Chain's attestation service that connects on-chain wallet addresses with off-chain information. It enables users to establish identity without exposing personally identifiable information (PII) directly.
Attestation Types
| Type | Description |
|---|---|
| Verified Address | KYC-verified wallet address |
| Balance Root | Merkle tree summary of balances |
| Verified Balance | Balance attestation at specific time |
| Verified Code | On-chain verification of off-chain codes |
useDojang Hook
import { useDojang } from 'giwa-react-native-wallet';
function DojangScreen() {
const {
getAttestation, // Get attestation by UID
isAttestationValid, // Check if attestation is valid
hasVerifiedAddress, // Check if address has verified attestation
getVerifiedBalance, // Get verified balance data
isLoading,
isInitializing,
error,
} = useDojang();
// ...
}
Get Attestation
const handleGetAttestation = async () => {
const attestationUid = '0x...'; // Attestation UID
try {
const attestation = await getAttestation(attestationUid);
if (attestation) {
console.log('Attester:', attestation.attester);
console.log('Recipient:', attestation.recipient);
console.log('Type:', attestation.attestationType);
console.log('Issued:', attestation.time);
console.log('Revoked:', attestation.revoked);
} else {
console.log('Attestation not found');
}
} catch (error) {
console.error('Lookup failed:', error.message);
}
};
Verify Attestation
Check if an attestation is valid (exists and not revoked):
const handleVerify = async () => {
const attestationUid = '0x...';
const isValid = await isAttestationValid(attestationUid);
if (isValid) {
console.log('Attestation is valid');
} else {
console.log('Attestation is invalid or revoked');
}
};
Get Verified Balance
For verified_balance type attestations:
const handleGetBalance = async () => {
const attestationUid = '0x...';
const result = await getVerifiedBalance(attestationUid);
if (result) {
console.log('Balance:', result.balance);
console.log('Timestamp:', result.timestamp);
}
};
Check Verified Address
Check if a wallet address has a verified attestation:
const handleCheckVerified = async () => {
const address = '0x742d35Cc6634C0532925a3b844Bc9e7595f...';
const isVerified = await hasVerifiedAddress(address);
if (isVerified) {
console.log('Address is verified');
} else {
console.log('Address is not verified');
}
};
Complete Example
import { useState } from 'react';
import { View, Text, TextInput, Button, Alert } from 'react-native';
import { useDojang } from 'giwa-react-native-wallet';
export function DojangScreen() {
const {
getAttestation,
isAttestationValid,
hasVerifiedAddress,
isLoading,
isInitializing,
error,
} = useDojang();
const [uid, setUid] = useState('');
const [attestation, setAttestation] = useState(null);
const handleLookup = async () => {
if (!uid) return;
const att = await getAttestation(uid);
setAttestation(att);
};
const handleVerify = async () => {
if (!uid) return;
const isValid = await isAttestationValid(uid);
Alert.alert(
'Verification Result',
isValid ? 'Valid attestation' : 'Invalid or revoked attestation'
);
};
const getTypeName = (type: string) => {
switch (type) {
case 'verified_address':
return 'Verified Address';
case 'balance_root':
return 'Balance Root';
case 'verified_balance':
return 'Verified Balance';
case 'verified_code':
return 'Verified Code';
default:
return type;
}
};
if (isInitializing) {
return <Text>Loading...</Text>;
}
return (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 20, marginBottom: 20 }}>Dojang Attestations</Text>
{error && (
<Text style={{ color: 'red', marginBottom: 10 }}>{error.message}</Text>
)}
<Text style={{ marginBottom: 5 }}>Attestation UID</Text>
<TextInput
placeholder="0x..."
value={uid}
onChangeText={setUid}
style={{
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
marginBottom: 10,
fontFamily: 'monospace',
}}
/>
<View style={{ flexDirection: 'row', marginBottom: 20 }}>
<Button title="Lookup" onPress={handleLookup} disabled={isLoading} />
<View style={{ width: 10 }} />
<Button title="Verify" onPress={handleVerify} disabled={isLoading} />
</View>
{attestation && (
<View
style={{
backgroundColor: attestation.revoked ? '#ffebee' : '#e8f5e9',
padding: 15,
borderRadius: 8,
}}
>
<Text style={{ fontWeight: 'bold', marginBottom: 10 }}>
{getTypeName(attestation.attestationType)}
</Text>
<Text>Attester: {attestation.attester.slice(0, 20)}...</Text>
<Text>Recipient: {attestation.recipient.slice(0, 20)}...</Text>
<Text>
Issued: {new Date(Number(attestation.time) * 1000).toLocaleString()}
</Text>
{attestation.revoked && (
<Text style={{ color: 'red', marginTop: 10 }}>
This attestation has been revoked
</Text>
)}
</View>
)}
</View>
);
}
Use Cases
Check if Address is Verified
const checkVerifiedAddress = async (address: string) => {
// Simple check using hasVerifiedAddress
const isVerified = await hasVerifiedAddress(address);
return isVerified;
};
// Or with detailed information
const checkVerifiedAddressDetailed = async (attestationUid: string) => {
const attestation = await getAttestation(attestationUid);
if (!attestation) {
return { verified: false, reason: 'Attestation not found' };
}
if (attestation.revoked) {
return { verified: false, reason: 'Attestation revoked' };
}
if (attestation.attestationType !== 'verified_address') {
return { verified: false, reason: 'Wrong attestation type' };
}
return { verified: true, address: attestation.recipient };
};
Verify Before Transaction
const sendToVerifiedAddress = async (attestationUid: string, amount: string) => {
// Verify attestation first
const isValid = await isAttestationValid(attestationUid);
if (!isValid) {
throw new Error('Invalid or revoked attestation');
}
// Get recipient address
const attestation = await getAttestation(attestationUid);
if (!attestation) {
throw new Error('Attestation not found');
}
// Send transaction
return sendTransaction({
to: attestation.recipient,
value: amount,
});
};