Skip to content

Commit 5a6e05c

Browse files
authored
Merge branch 'main' into feature/automated-compliance-checks
2 parents 0973564 + 104e887 commit 5a6e05c

36 files changed

Lines changed: 5227 additions & 131 deletions

GOVERNANCE_TOKEN.md

Lines changed: 441 additions & 0 deletions
Large diffs are not rendered by default.

api/src/bridge.ts

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import { ApiClient } from './client';
2+
import { Trade } from './models';
3+
4+
export interface BridgeProvider {
5+
name: string;
6+
oracle_address: string;
7+
is_active: boolean;
8+
fee_bps: number;
9+
supported_chains: string[];
10+
max_trade_amount: string;
11+
min_trade_amount: string;
12+
}
13+
14+
export interface CrossChainTrade {
15+
trade_id: number;
16+
source_chain: string;
17+
dest_chain: string;
18+
source_tx_hash: string;
19+
bridge_provider: string;
20+
attestation_id: string;
21+
attestation_status: 'pending' | 'confirmed' | 'failed' | 'expired';
22+
attestation_timestamp: number;
23+
retry_count: number;
24+
current_confirmations: number;
25+
bridge_fee: string;
26+
}
27+
28+
export interface BridgeAttestation {
29+
attestation_id: string;
30+
trade_id: number;
31+
source_chain: string;
32+
source_tx_hash: string;
33+
amount: string;
34+
recipient: string;
35+
timestamp: number;
36+
signature: string;
37+
provider: string;
38+
}
39+
40+
export interface BridgeValidation {
41+
valid: boolean;
42+
error_code?: number;
43+
error_message?: string;
44+
confirmations: number;
45+
}
46+
47+
export interface ProviderStatus {
48+
provider: string;
49+
healthy: boolean;
50+
latency_ms: number;
51+
last_check: number;
52+
error?: string;
53+
}
54+
55+
/**
56+
* Bridge API for cross-chain trade operations
57+
*/
58+
export class BridgeApi {
59+
constructor(private client: ApiClient) {}
60+
61+
/**
62+
* Register a new bridge provider
63+
*/
64+
async registerProvider(provider: Partial<BridgeProvider>): Promise<BridgeProvider> {
65+
return this.client.post('/bridge/providers', provider);
66+
}
67+
68+
/**
69+
* Get all registered bridge providers
70+
*/
71+
async getProviders(): Promise<BridgeProvider[]> {
72+
return this.client.get('/bridge/providers');
73+
}
74+
75+
/**
76+
* Get a specific bridge provider
77+
*/
78+
async getProvider(name: string): Promise<BridgeProvider> {
79+
return this.client.get(`/bridge/providers/${name}`);
80+
}
81+
82+
/**
83+
* Deactivate a bridge provider
84+
*/
85+
async deactivateProvider(name: string): Promise<void> {
86+
return this.client.delete(`/bridge/providers/${name}`);
87+
}
88+
89+
/**
90+
* Create a cross-chain trade
91+
*/
92+
async createCrossChainTrade(
93+
tradeId: number,
94+
sourceChain: string,
95+
sourceTxHash: string,
96+
bridgeProvider: string,
97+
attestationId: string,
98+
bridgeFee: string
99+
): Promise<CrossChainTrade> {
100+
return this.client.post('/bridge/trades', {
101+
trade_id: tradeId,
102+
source_chain: sourceChain,
103+
source_tx_hash: sourceTxHash,
104+
bridge_provider: bridgeProvider,
105+
attestation_id: attestationId,
106+
bridge_fee: bridgeFee,
107+
});
108+
}
109+
110+
/**
111+
* Get cross-chain trade info
112+
*/
113+
async getCrossChainTrade(tradeId: number): Promise<CrossChainTrade> {
114+
return this.client.get(`/bridge/trades/${tradeId}`);
115+
}
116+
117+
/**
118+
* Submit bridge attestation
119+
*/
120+
async submitAttestation(attestation: BridgeAttestation): Promise<BridgeValidation> {
121+
return this.client.post('/bridge/attestations', attestation);
122+
}
123+
124+
/**
125+
* Get attestation status
126+
*/
127+
async getAttestationStatus(attestationId: string): Promise<BridgeValidation> {
128+
return this.client.get(`/bridge/attestations/${attestationId}`);
129+
}
130+
131+
/**
132+
* Retry failed attestation
133+
*/
134+
async retryAttestation(tradeId: number): Promise<void> {
135+
return this.client.post(`/bridge/trades/${tradeId}/retry`, {});
136+
}
137+
138+
/**
139+
* Rollback failed cross-chain trade
140+
*/
141+
async rollbackTrade(tradeId: number, reason: string): Promise<CrossChainTrade> {
142+
return this.client.post(`/bridge/trades/${tradeId}/rollback`, { reason });
143+
}
144+
145+
/**
146+
* Get bridge provider health status
147+
*/
148+
async getProviderStatus(provider: string): Promise<ProviderStatus> {
149+
return this.client.get(`/bridge/providers/${provider}/status`);
150+
}
151+
152+
/**
153+
* Get all provider statuses
154+
*/
155+
async getAllProviderStatuses(): Promise<ProviderStatus[]> {
156+
return this.client.get('/bridge/providers/status/all');
157+
}
158+
159+
/**
160+
* Pause bridge operations
161+
*/
162+
async pauseBridge(): Promise<void> {
163+
return this.client.post('/bridge/pause', {});
164+
}
165+
166+
/**
167+
* Resume bridge operations
168+
*/
169+
async resumeBridge(): Promise<void> {
170+
return this.client.post('/bridge/resume', {});
171+
}
172+
173+
/**
174+
* Get bridge operational status
175+
*/
176+
async getBridgeStatus(): Promise<{ paused: boolean; providers_active: number }> {
177+
return this.client.get('/bridge/status');
178+
}
179+
180+
/**
181+
* Query cross-chain trades with filters
182+
*/
183+
async queryCrossChainTrades(filters: {
184+
source_chain?: string;
185+
bridge_provider?: string;
186+
attestation_status?: string;
187+
limit?: number;
188+
offset?: number;
189+
}): Promise<{ items: CrossChainTrade[]; total: number; has_more: boolean }> {
190+
const params = new URLSearchParams();
191+
if (filters.source_chain) params.append('source_chain', filters.source_chain);
192+
if (filters.bridge_provider) params.append('bridge_provider', filters.bridge_provider);
193+
if (filters.attestation_status) params.append('attestation_status', filters.attestation_status);
194+
if (filters.limit) params.append('limit', filters.limit.toString());
195+
if (filters.offset) params.append('offset', filters.offset.toString());
196+
197+
return this.client.get(`/bridge/trades?${params}`);
198+
}
199+
200+
/**
201+
* Get bridge statistics
202+
*/
203+
async getBridgeStats(): Promise<{
204+
total_cross_chain_trades: number;
205+
successful_attestations: number;
206+
failed_attestations: number;
207+
total_bridge_volume: string;
208+
average_confirmation_time_secs: number;
209+
}> {
210+
return this.client.get('/bridge/stats');
211+
}
212+
}

api/src/contracts.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,18 @@ export function isTrade(value: unknown): value is Trade {
3838
);
3939
}
4040

41+
const EVENT_CATEGORIES = new Set<string>([
42+
'trade', 'arb', 'fee', 'tmpl', 'sub', 'gov', 'sys', 'ins', 'oracle',
43+
]);
44+
4145
export function isEvent(value: unknown): value is Event {
4246
return (
4347
isRecord(value) &&
4448
typeof value.id === 'string' &&
4549
typeof value.type === 'string' &&
50+
typeof value.category === 'string' &&
51+
EVENT_CATEGORIES.has(value.category) &&
52+
typeof value.schemaVersion === 'number' &&
4653
typeof value.tradeId === 'string' &&
4754
typeof value.timestamp === 'string' &&
4855
isRecord(value.data)

api/src/models.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,41 @@ export interface Trade {
88
timestamp: string;
99
}
1010

11+
/** High-level event categories matching the contract's topic layout. */
12+
export type EventCategory =
13+
| 'trade'
14+
| 'arb'
15+
| 'fee'
16+
| 'tmpl'
17+
| 'sub'
18+
| 'gov'
19+
| 'sys'
20+
| 'ins'
21+
| 'oracle';
22+
1123
export interface Event {
1224
id: string;
25+
/** Canonical snake_case event name, e.g. "trade_created" */
1326
type: string;
27+
/** High-level category for client-side filtering */
28+
category: EventCategory;
29+
/** Schema version from the contract payload (v field) */
30+
schemaVersion: number;
1431
tradeId: string;
1532
timestamp: string;
16-
data: Record<string, any>;
33+
data: Record<string, unknown>;
34+
}
35+
36+
/** Query parameters accepted by GET /events */
37+
export interface EventFilterParams {
38+
limit?: number;
39+
offset?: number;
40+
event_type?: string;
41+
category?: EventCategory;
42+
trade_id?: string;
43+
from_ledger?: number;
44+
to_ledger?: number;
45+
from_time?: string;
46+
to_time?: string;
47+
contract_id?: string;
1748
}

api/src/resources.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ApiClient } from './client';
2-
import { Event, Trade } from './models';
2+
import { Event, EventCategory, EventFilterParams, Trade } from './models';
33

44
export class TradesApi {
55
constructor(private client: ApiClient) {}
@@ -28,16 +28,29 @@ export class TradesApi {
2828
export class EventsApi {
2929
constructor(private client: ApiClient) {}
3030

31-
async getEvents(limit = 100, tradeId?: string): Promise<Event[]> {
32-
const params = new URLSearchParams({ limit: limit.toString() });
33-
if (tradeId) params.append('tradeId', tradeId);
31+
async getEvents(filters: EventFilterParams = {}): Promise<Event[]> {
32+
const params = new URLSearchParams();
33+
if (filters.limit !== undefined) params.set('limit', filters.limit.toString());
34+
if (filters.offset !== undefined) params.set('offset', filters.offset.toString());
35+
if (filters.event_type) params.set('event_type', filters.event_type);
36+
if (filters.category) params.set('category', filters.category);
37+
if (filters.trade_id) params.set('trade_id', filters.trade_id);
38+
if (filters.from_ledger !== undefined) params.set('from_ledger', filters.from_ledger.toString());
39+
if (filters.to_ledger !== undefined) params.set('to_ledger', filters.to_ledger.toString());
40+
if (filters.from_time) params.set('from_time', filters.from_time);
41+
if (filters.to_time) params.set('to_time', filters.to_time);
42+
if (filters.contract_id) params.set('contract_id', filters.contract_id);
3443
return this.client.get(`/events?${params}`);
3544
}
3645

3746
async getEventsByTrade(tradeId: string): Promise<Event[]> {
3847
return this.client.get(`/events/trade/${tradeId}`);
3948
}
4049

50+
async getEventsByCategory(category: EventCategory, limit = 50): Promise<Event[]> {
51+
return this.getEvents({ category, limit });
52+
}
53+
4154
async getEvent(id: string): Promise<Event> {
4255
return this.client.get(`/events/${id}`);
4356
}

0 commit comments

Comments
 (0)