Skip to content
Merged
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
55 changes: 40 additions & 15 deletions packages/adapters/rebalance/src/adapters/stargate/stargate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import { jsonifyError, Logger } from '@mark/logger';
import { BridgeAdapter, MemoizedTransactionRequest, RebalanceTransactionMemo } from '../../types';
import { STARGATE_OFT_ABI } from './abi';
import {
STARGATE_USDT_POOL_ETH,
USDT_ETH,
LZ_ENDPOINT_ID_TON,
STARGATE_POOL_ADDRESSES,
CHAIN_ID_TO_LZ_ENDPOINT,
StargateSendParam,
StargateMessagingFee,
LzMessageStatus,
Expand All @@ -27,6 +27,7 @@ import {
tonAddressToBytes32,
USDT_TON_STARGATE,
} from './types';
import { getDestinationAssetAddress } from '../../shared/asset';

// LayerZero Scan API base URL
const LZ_SCAN_API_URL = 'https://scan.layerzero-api.com';
Expand Down Expand Up @@ -56,6 +57,26 @@ export class StargateBridgeAdapter implements BridgeAdapter {
return SupportedBridge.Stargate;
}

/**
* Resolve the destination token address for a route
* For TON, uses the Stargate-specific hex address; for EVM chains, looks up via chain config
*/
private resolveDstToken(route: RebalanceRoute): string | null {
if (route.destination === 30826) return USDT_TON_STARGATE;
return (
getDestinationAssetAddress(route.asset, route.origin, route.destination, this.chains, this.logger) ?? null
);
}

/**
* Get the LayerZero endpoint ID for a chain
*/
protected getLzEndpointId(chainId: number): number {
const eid = CHAIN_ID_TO_LZ_ENDPOINT[chainId];
if (eid === undefined) throw new Error(`No LayerZero endpoint ID configured for chain ${chainId}`);
return eid;
}

/**
* Get the expected amount received after bridging via Stargate
*
Expand Down Expand Up @@ -99,8 +120,11 @@ export class StargateBridgeAdapter implements BridgeAdapter {
return null;
}

// For TON destination, use the Stargate-specific token address format
const dstToken = route.destination === 30826 ? USDT_TON_STARGATE : route.asset;
const dstToken = this.resolveDstToken(route);
if (!dstToken) {
this.logger.warn('Could not resolve destination token', { route });
return null;
}

// Use a placeholder address for quote - actual address will be used in send()
const placeholderAddress = '0x1234567890abcdef1234567890abcdef12345678';
Expand Down Expand Up @@ -162,7 +186,7 @@ export class StargateBridgeAdapter implements BridgeAdapter {

// Prepare send parameters for quote
const sendParam: StargateSendParam = {
dstEid: LZ_ENDPOINT_ID_TON,
dstEid: this.getLzEndpointId(route.destination),
to: pad('0x0000000000000000000000000000000000000000' as `0x${string}`, { size: 32 }),
amountLD: BigInt(amount),
minAmountLD: BigInt(0), // Will be calculated after quote
Expand Down Expand Up @@ -304,8 +328,11 @@ export class StargateBridgeAdapter implements BridgeAdapter {
return null;
}

// For TON destination, use the Stargate-specific token address format
const dstToken = route.destination === 30826 ? USDT_TON_STARGATE : route.asset;
const dstToken = this.resolveDstToken(route);
if (!dstToken) {
this.logger.warn('Could not resolve destination token', { route });
return null;
}

// Calculate minimum amount with slippage (0.5%)
const slippageBps = 50n;
Expand Down Expand Up @@ -471,7 +498,7 @@ export class StargateBridgeAdapter implements BridgeAdapter {

// Prepare send parameters
const sendParam: StargateSendParam = {
dstEid: LZ_ENDPOINT_ID_TON,
dstEid: this.getLzEndpointId(route.destination),
to: recipientBytes32,
amountLD: BigInt(amount),
minAmountLD: minAmount,
Expand Down Expand Up @@ -745,13 +772,11 @@ export class StargateBridgeAdapter implements BridgeAdapter {
* Get the Stargate pool address for an asset
*/
protected getPoolAddress(asset: string, chainId: number): `0x${string}` {
// For USDT on Ethereum mainnet
if (asset.toLowerCase() === USDT_ETH.toLowerCase() && chainId === 1) {
return STARGATE_USDT_POOL_ETH;
}

// Add more pool addresses as needed
throw new Error(`No Stargate pool found for asset ${asset} on chain ${chainId}`);
const chainPools = STARGATE_POOL_ADDRESSES[chainId];
if (!chainPools) throw new Error(`No Stargate pools configured for chain ${chainId}`);
const pool = chainPools[asset.toLowerCase()];
if (!pool) throw new Error(`No Stargate pool found for asset ${asset} on chain ${chainId}`);
return pool;
}

/**
Expand Down
53 changes: 53 additions & 0 deletions packages/adapters/rebalance/src/adapters/stargate/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,47 @@ export const STARGATE_USDT_POOL_ETH = '0x933597a323Eb81cAe705C5bC29985172fd5A397
// USDT token on Ethereum mainnet
export const USDT_ETH = '0xdAC17F958D2ee523a2206206994597C13D831ec7' as `0x${string}`;

// Token addresses - Base
export const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as `0x${string}`;

// Token addresses - Arbitrum
export const USDC_ARB = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' as `0x${string}`;
export const USDT_ARB = '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' as `0x${string}`;

// Token addresses - Mantle
export const USDC_MANTLE = '0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9' as `0x${string}`;
export const USDT_MANTLE = '0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE' as `0x${string}`;

// Stargate Pool addresses - Base
export const STARGATE_USDC_POOL_BASE = '0x27a16dc786820B16E5c9028b75B99F6f604b5d26' as `0x${string}`;

// Stargate Pool addresses - Arbitrum
export const STARGATE_USDC_POOL_ARB = '0xe8CDF27AcD73a434D661C84887215F7598e7d0d3' as `0x${string}`;
export const STARGATE_USDT_POOL_ARB = '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0' as `0x${string}`;

// Stargate Pool addresses - Mantle
export const STARGATE_USDC_POOL_MANTLE = '0xAc290Ad4e0c891FDc295ca4F0a6214cf6dC6acDC' as `0x${string}`;
export const STARGATE_USDT_POOL_MANTLE = '0xB715B85682B731dB9D5063187C450095c91C57FC' as `0x${string}`;

// ============================================================================
// LayerZero V2 Endpoint IDs
// Reference: https://docs.layerzero.network/v2/deployments/chains
// ============================================================================

export const LZ_ENDPOINT_ID_ETH = 30101; // Ethereum mainnet
export const LZ_ENDPOINT_ID_BASE = 30184; // Base mainnet
export const LZ_ENDPOINT_ID_ARB = 30110; // Arbitrum mainnet
export const LZ_ENDPOINT_ID_MANTLE = 30181; // Mantle mainnet
export const LZ_ENDPOINT_ID_TON = 30826; // TON mainnet

export const CHAIN_ID_TO_LZ_ENDPOINT: Record<number, number> = {
1: LZ_ENDPOINT_ID_ETH,
8453: LZ_ENDPOINT_ID_BASE,
42161: LZ_ENDPOINT_ID_ARB,
5000: LZ_ENDPOINT_ID_MANTLE,
30826: LZ_ENDPOINT_ID_TON,
};

// ============================================================================
// Chain IDs
// ============================================================================
Expand All @@ -36,6 +69,23 @@ export const TAC_CHAIN_ID = 239;
// TON does not have an EVM chain ID, we use LayerZero endpoint ID
export const TON_CHAIN_ID = 30826;

// ============================================================================
// Stargate Pool Addresses
// ============================================================================

export const STARGATE_POOL_ADDRESSES: Record<number, Record<string, `0x${string}`>> = {
1: { [USDT_ETH.toLowerCase()]: STARGATE_USDT_POOL_ETH },
8453: { [USDC_BASE.toLowerCase()]: STARGATE_USDC_POOL_BASE },
42161: {
[USDC_ARB.toLowerCase()]: STARGATE_USDC_POOL_ARB,
[USDT_ARB.toLowerCase()]: STARGATE_USDT_POOL_ARB,
},
5000: {
[USDC_MANTLE.toLowerCase()]: STARGATE_USDC_POOL_MANTLE,
[USDT_MANTLE.toLowerCase()]: STARGATE_USDT_POOL_MANTLE,
},
};

// ============================================================================
// Stargate API Configuration
// Reference: https://stargate.finance/api/v1/quotes
Expand Down Expand Up @@ -122,6 +172,9 @@ export const USDT_TON_STARGATE = '0xb113a994b5024a16719f69139328eb759596c38a25f5
*/
export const STARGATE_CHAIN_NAMES: Record<number, string> = {
1: 'ethereum',
8453: 'base',
42161: 'arbitrum',
5000: 'mantle',
30826: 'ton',
239: 'tac',
};
Expand Down
Loading