kleros-escrow-data-service
Version:
Data service for interacting with Kleros Escrow
248 lines (220 loc) • 5.97 kB
Markdown
# 🤝 Kleros Escrow Transaction Explorer
A lovable web app to explore and manage Kleros escrow transactions. View all transactions or look up specific ones by ID.
## 🚀 Quick Start
```bash
# Install dependencies
yarn add kleros-escrow-data-service ethers@5 graphql-request graphql
```
## 📦 Initialize Kleros Client
```typescript
import { createKlerosEscrowClient } from "kleros-escrow-data-service";
const config = {
provider: {
url: "https://ethereum.publicnode.com",
networkId: 1, // Ethereum mainnet
},
multipleArbitrableTransaction: {
address: "0x0d67440946949FE293B45c52eFD8A9b3d51e2522",
},
ipfsGateway: "https://cdn.kleros.link",
};
// For read-only operations
const readOnlyClient = createKlerosEscrowClient(config);
// For transactions (with wallet)
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const signerClient = createKlerosEscrowClient(config, signer);
```
## 🔍 Core Functions & Types
### 1. Get All Transactions
```typescript
// Fetch all transactions from the subgraph
const allTransactions = await klerosClient.services.event.getAllMetaEvidence();
interface MetaEvidenceEvent {
id: string;
blockTimestamp: string;
transactionHash: string;
_evidence: string;
blockNumber: string;
_metaEvidenceID: string;
}
// IPFS Content Type
interface MetaEvidence {
category: string;
title: string;
description: string;
question: string;
rulingOptions: {
type: string;
titles: string[];
descriptions: string[];
};
subCategory?: string;
sender?: string;
receiver?: string;
amount?: string;
timeout?: number;
fileURI?: string;
fileTypeExtension?: string;
}
```
### 2. Get Transaction Details
```typescript
// Get all events for a specific transaction
const details = await klerosClient.services.event.getTransactionDetails(transactionId);
interface TransactionEvents {
metaEvidences: {
id: string;
blockTimestamp: string;
transactionHash: string;
_evidence: string;
blockNumber: string;
}[];
payments: {
id: string;
_transactionID: string;
_amount: string;
_party: string;
blockNumber: string;
blockTimestamp: string;
transactionHash: string;
}[];
evidences: {
_arbitrator: string;
_party: string;
_evidence: string;
_evidenceGroupID: string;
blockNumber: string;
transactionHash: string;
}[];
disputes: {
_arbitrator: string;
_disputeID: string;
blockNumber: string;
blockTimestamp: string;
_metaEvidenceID: string;
_evidenceGroupID: string;
transactionHash: string;
}[];
hasToPayFees: {
_transactionID: string;
blockNumber: string;
blockTimestamp: string;
_party: string;
transactionHash: string;
}[];
rulings: {
_arbitrator: string;
_disputeID: string;
blockNumber: string;
blockTimestamp: string;
_ruling: string;
transactionHash: string;
}[];
}
```
## 🏠 Implementation Guide
### Transaction List Component
```typescript
function TransactionList() {
const [transactions, setTransactions] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadTransactions = async () => {
try {
const allTx = await klerosClient.services.event.getAllMetaEvidence();
const processedTx = await Promise.all(
allTx.map(async (tx) => {
const metaData = await safeLoadIPFS(tx._evidence);
return {
id: tx._metaEvidenceID,
timestamp: new Date(parseInt(tx.blockTimestamp) * 1000),
title: metaData.title,
description: metaData.description,
amount: metaData.amount,
category: metaData.category,
sender: metaData.sender,
receiver: metaData.receiver,
transactionHash: tx.transactionHash,
blockNumber: tx.blockNumber
};
})
);
setTransactions(processedTx);
} catch (error) {
console.error('Failed to load transactions:', error);
} finally {
setLoading(false);
}
};
loadTransactions();
}, []);
return (
<div className="transaction-grid">
{transactions.map(tx => (
<TransactionCard
key={tx.id}
transaction={tx}
onClick={() => openTransactionModal(tx.id)}
/>
))}
</div>
);
}
```
### Utility Functions
```typescript
// Safe IPFS Loading
const safeLoadIPFS = async (uri: string) => {
try {
return await klerosClient.services.ipfs.fetchFromIPFS(uri);
} catch (error) {
console.error(`Failed to load IPFS content for ${uri}:`, error);
return {
title: 'Failed to load',
description: 'Content unavailable',
category: 'Unknown',
amount: '0'
};
}
};
// Sorting and Filtering
const sortByDate = (tx) => [...tx].sort((a, b) => b.timestamp - a.timestamp);
const filterByCategory = (tx, category) => tx.filter(t => t.category === category);
const searchTransactions = (tx, term) => tx.filter(t =>
t.title.toLowerCase().includes(term) ||
t.description.toLowerCase().includes(term)
);
```
### Styling
```css
.transaction-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
padding: 1rem;
}
.card {
background: var(--card-bg);
border-radius: 12px;
padding: 1rem;
transition: transform 0.2s;
cursor: pointer;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
```
## 💡 Best Practices
1. **Performance**
- Use virtual scrolling for large lists
- Cache IPFS responses
- Implement batch loading
- Add debounced search
2. **UI/UX**
- Show loading states and error messages
- Color-code transaction statuses
- Support dark/light mode
- Add ENS support for addresses
- Format timestamps and amounts consistently