Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ THIRDWEB_SECRET_KEY=
HASHKEY_RPC_URL=https://testnet.hsk.xyz
GRIFFIN_VAULT_ADDRESS=
GRIFFIN_OPERATOR_PRIVATE_KEY=
GRIFFIN_DEX_ADDRESS=
GRIFFIN_DEX_ADDRESS=

# Bridging
SUPERBRIDGE_API_KEY=
1 change: 1 addition & 0 deletions packages/orchestrator/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ GRIFFIN_DEX_ADDRESS= # Deployed GriffinDEX contract address
ONEINCH_API_KEY=your-1inch-api-key
THIRDWEB_CLIENT_ID=your-thirdweb-client-id
THIRDWEB_SECRET_KEY=your-thirdweb-secret-key
SUPERBRIDGE_API_KEY= # Superbridge API key for cross-chain bridging

# Security
JWT_SECRET=your-jwt-secret-key
Expand Down
375 changes: 375 additions & 0 deletions packages/orchestrator/logs/combined.log

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions packages/orchestrator/logs/error.log

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions packages/orchestrator/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ import { HealthService } from "./services/HealthService";
import { SettlementEngine } from "./settlement/SettlementEngine";
import { InventorySettler } from "./settlement/InventorySettler";
import { SwapSettler } from "./settlement/SwapSettler";
import { BridgeSettler } from "./settlement/BridgeSettler";
import { EvmClient } from "./blockchain/evm/EvmClient";
import { DexClient } from "./blockchain/evm/DexClient";
import { SuperbridgeClient } from "./blockchain/superbridge/SuperbridgeClient";
import { type IChainClient } from "./blockchain/IChainClient";
import { type IDexClient } from "./blockchain/IDexClient";
import { type IBridgeClient } from "./blockchain/IBridgeClient";

// Import routes
import intentRoutes from "./routes/intents";
Expand Down Expand Up @@ -60,10 +63,25 @@ if (config.blockchain.hashkey.operatorPrivateKey && config.blockchain.hashkey.de
logger.warn("GRIFFIN_DEX_ADDRESS not set — SwapSettler will decline all intents");
}

// Bridge clients — ordered by preference
const bridgeClients: IBridgeClient[] = [];

if (config.external.superbridge.apiKey && config.blockchain.hashkey.operatorPrivateKey) {
bridgeClients.push(
new SuperbridgeClient({
apiKey: config.external.superbridge.apiKey,
senderAddress: config.blockchain.hashkey.vaultAddress,
}),
);
} else {
logger.warn("SUPERBRIDGE_API_KEY not set — BridgeSettler will decline all cross-chain intents");
}

const routeService = new RouteService();
const settlementEngine = new SettlementEngine([
new InventorySettler(chainClients, config.blockchain.hashkey.vaultAddress),
new SwapSettler(dexClients, chainClients),
new BridgeSettler(bridgeClients, chainClients, config.blockchain.hashkey.vaultAddress),
]);
const intentService = new IntentService(settlementEngine);
// -----------------------------------------------------------------------------
Expand Down
119 changes: 119 additions & 0 deletions packages/orchestrator/src/blockchain/IBridgeClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* A single step within a bridge route.
* Bridges often require multiple on-chain transactions (e.g. approve + bridge).
*/
export interface BridgeStep {
/** Step index within the route (0-based) */
index: number;
/** Human-readable description, e.g. "Approve USDC" or "Bridge via Superbridge" */
description: string;
/** Chain this step is executed on */
chainId: string;
/** Whether this step requires an ERC-20 approval before execution */
requiresApproval: boolean;
}

/**
* A bridge route returned by getRoutes().
* Represents one provider's offer to move tokens cross-chain.
*/
export interface BridgeRoute {
/** Opaque route identifier — pass back to getStepTransaction() */
routeId: string;
/** Provider name, e.g. "superbridge", "across", "hop" */
provider: string;
/** Source chain */
fromChain: string;
/** Destination chain */
toChain: string;
/** Token address on source chain */
fromToken: string;
/** Token address on destination chain */
toToken: string;
/** Input amount in raw token units */
amountIn: string;
/** Expected output amount in raw token units */
amountOut: string;
/** Estimated time for the bridge to complete, in seconds */
estimatedTimeSeconds: number;
/** Total fees in USD (approximate) */
feesUsd: string;
/** Ordered list of steps the user must execute */
steps: BridgeStep[];
}

/**
* The calldata needed to execute one step of a bridge route.
*/
export interface BridgeStepTransaction {
/** Chain to submit this transaction on */
chainId: string;
/** Contract to call */
to: string;
/** Encoded calldata */
data: string;
/** Native value to send with the transaction (in wei) */
value: string;
/** Gas limit estimate */
gasLimit?: string;
}

// ---------------------------------------------------------------------------

/**
* Interface every bridge provider client must implement.
*
* Implementations can be:
* - SDK wrappers (e.g. SuperbridgeClient using @superbridge-app/sdk)
* - HTTP API clients (e.g. AcrossClient, HopClient)
*
* BridgeSettler depends only on this interface — never on a concrete client.
*
* Unlike IDexClient, bridge clients are inherently cross-chain so chainId
* is part of the route rather than a per-call parameter.
*/
export interface IBridgeClient {
/** Human-readable name for logging, e.g. "superbridge", "across" */
readonly name: string;

/**
* Returns available bridge routes for moving `amount` of `fromToken`
* on `fromChain` to `toToken` on `toChain`.
*
* Returns an empty array if no routes are available.
* Must not submit any transaction or have side effects.
*/
getRoutes(
fromChain: string,
toChain: string,
fromToken: string,
toToken: string,
amount: string,
): Promise<BridgeRoute[]>;

/**
* Returns the transaction calldata needed to execute a specific step
* of a previously fetched route.
*
* @param routeId - The routeId from a BridgeRoute
* @param stepIndex - Which step to build the transaction for
* @param sender - Address submitting the transaction (Griffin's operator wallet)
* @param recipient - Final destination address for the bridged tokens
*/
getStepTransaction(
routeId: string,
stepIndex: number,
sender: string,
recipient: string,
): Promise<BridgeStepTransaction>;

/**
* Waits for a bridge transaction to be fully confirmed on the destination chain.
* For multi-step bridges this should be called after the final step.
*
* @param txHash - Transaction hash of the submitted bridge transaction
* @param fromChain - Source chain ID
* @param toChain - Destination chain ID
*/
waitForCompletion(txHash: string, fromChain: string, toChain: string): Promise<void>;
}
8 changes: 8 additions & 0 deletions packages/orchestrator/src/blockchain/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
export type { IChainClient } from "./IChainClient";
export type { IDexClient, DexQuote } from "./IDexClient";
export type {
IBridgeClient,
BridgeRoute,
BridgeStep,
BridgeStepTransaction,
} from "./IBridgeClient";
export { EvmClient } from "./evm/EvmClient";
export { DexClient } from "./evm/DexClient";
export { StellarClient } from "./stellar/StellarClient";
export { SuperbridgeClient } from "./superbridge/SuperbridgeClient";
export type { EvmClientConfig } from "./evm/EvmClient";
export type { DexClientConfig } from "./evm/DexClient";
export type { SuperbridgeClientConfig } from "./superbridge/SuperbridgeClient";
Loading
Loading