Skip to content

Commit 4be09aa

Browse files
authored
Merge pull request #491 from everclearorg/prod
2 parents e91e920 + 26579a3 commit 4be09aa

6 files changed

Lines changed: 64 additions & 25 deletions

File tree

docker/admin/Dockerfile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,11 @@ COPY yarn.lock /tmp/build/
5050
# Install dependencies including devDependencies
5151
# Note: --mode=skip-build skips preinstall/postinstall scripts during install
5252
# This avoids the "npx only-allow pnpm" check in @eth-optimism/core-utils
53-
# Then we run rebuild to build native modules with our build tools
54-
RUN yarn install --immutable --mode=skip-build && \
53+
# Clear yarn cache before install to avoid corrupted package downloads
54+
# Retry install on failure to handle transient npm registry issues
55+
RUN yarn cache clean --all && \
56+
yarn install --immutable --mode=skip-build || \
57+
(yarn cache clean --all && sleep 2 && yarn install --immutable --mode=skip-build) && \
5558
yarn workspaces foreach -A run rebuild
5659

5760
# Copy source files

docker/poller/Dockerfile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,11 @@ COPY yarn.lock /tmp/build/
5050
# Install dependencies including devDependencies
5151
# Note: --mode=skip-build skips preinstall/postinstall scripts during install
5252
# This avoids the "npx only-allow pnpm" check in @eth-optimism/core-utils
53-
# Then we run rebuild to build native modules with our build tools
54-
RUN yarn install --immutable --mode=skip-build && \
53+
# Clear yarn cache before install to avoid corrupted package downloads
54+
# Retry install on failure to handle transient npm registry issues
55+
RUN yarn cache clean --all && \
56+
yarn install --immutable --mode=skip-build || \
57+
(yarn cache clean --all && sleep 2 && yarn install --immutable --mode=skip-build) && \
5558
yarn workspaces foreach -A run rebuild
5659

5760
# Copy source files

packages/adapters/database/src/db.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ export async function getRebalanceOperationByRecipient(
906906
}
907907

908908
if (recipient) {
909-
conditions.push(`ro."recipient" = $${paramCount}`);
909+
conditions.push(`LOWER(ro."recipient") = LOWER($${paramCount})`);
910910
values.push(recipient);
911911
paramCount++;
912912
}

packages/poller/src/init.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ function initializeAdapters(config: MarkConfiguration, logger: Logger): MarkAdap
186186
web3Signer as EthWallet,
187187
logger,
188188
);
189-
189+
190190
// Initialize fill service chain service if FS signer URL is configured
191191
// This allows TAC rebalancing to use a separate sender address for FS
192192
// senderAddress defaults to fillService.address if not explicitly set (same key = same address)
@@ -328,6 +328,7 @@ export const initPoller = async (): Promise<{ statusCode: number; body: string }
328328
try {
329329
adapters = initializeAdapters(config, logger);
330330
const addresses = await adapters.chainService.getAddress();
331+
const fillServiceAddresses = adapters.fillServiceChainService ? await adapters.fillServiceChainService.getAddress() : undefined;
331332

332333
const context: ProcessingContext = {
333334
...adapters,
@@ -346,6 +347,7 @@ export const initPoller = async (): Promise<{ statusCode: number; body: string }
346347
stage: config.stage,
347348
environment: config.environment,
348349
addresses,
350+
fillServiceAddresses
349351
});
350352

351353
const rebalanceOperations = await rebalanceMantleEth(context);
@@ -376,6 +378,7 @@ export const initPoller = async (): Promise<{ statusCode: number; body: string }
376378
stage: config.stage,
377379
environment: config.environment,
378380
addresses,
381+
fillServiceAddresses
379382
});
380383

381384
const rebalanceOperations = await rebalanceTacUsdt(context);
@@ -406,6 +409,7 @@ export const initPoller = async (): Promise<{ statusCode: number; body: string }
406409
stage: config.stage,
407410
environment: config.environment,
408411
addresses,
412+
fillServiceAddresses
409413
});
410414

411415
const rebalanceOperations = await rebalanceSolanaUsdc(context);
@@ -438,6 +442,7 @@ export const initPoller = async (): Promise<{ statusCode: number; body: string }
438442
stage: config.stage,
439443
environment: config.environment,
440444
addresses,
445+
fillServiceAddresses
441446
});
442447

443448
invoiceResult = await pollAndProcessInvoices(context);

packages/poller/src/rebalance/mantleEth.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -324,15 +324,17 @@ const evaluateFillServiceRebalance = async (
324324
continue;
325325
}
326326

327-
// Check if an active earmark already exists for this intent before executing operations
328-
const existingActive = await database.getActiveEarmarkForInvoice(intent.intent_id);
327+
// Check if an earmark already exists for this intent before executing operations
328+
const existingEarmarks = await database.getEarmarks({
329+
invoiceId: intent.intent_id,
330+
});
329331

330-
if (existingActive) {
331-
logger.warn('Active earmark already exists for intent, skipping rebalance operations', {
332+
if (existingEarmarks.length > 0) {
333+
logger.warn('Earmark already exists for intent, skipping rebalance operations', {
332334
requestId,
333335
invoiceId: intent.intent_id,
334-
existingEarmarkId: existingActive.id,
335-
existingStatus: existingActive.status,
336+
existingEarmarkId: existingEarmarks[0].id,
337+
existingStatus: existingEarmarks[0].status,
336338
});
337339
continue;
338340
}
@@ -441,6 +443,18 @@ const evaluateFillServiceRebalance = async (
441443
// PRIORITY 2: Threshold Rebalancing (FS → FS)
442444
// FS sender does not have enough funds on Mantle, rebalance from WETH on Mainnet
443445
// Get FS receiver's mETH balance
446+
const { operations: inFlightOps } = await database.getRebalanceOperations(undefined, undefined, {
447+
status: [RebalanceOperationStatus.PENDING, RebalanceOperationStatus.AWAITING_CALLBACK],
448+
bridge: [SupportedBridge.Mantle, `${SupportedBridge.Across}-mantle`],
449+
earmarkId: null
450+
});
451+
if(inFlightOps.length) {
452+
logger.info(`Found inflight rebalance operations ${inFlightOps.length}. Threshold rebalancing skipping....`, {
453+
requestId,
454+
});
455+
return actions;
456+
}
457+
444458
let fsReceiverMethBalance = 0n;
445459
if (fsConfig.address) {
446460
try {

packages/poller/src/rebalance/tacUsdt.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
convertToNativeUnits,
99
convertTo18Decimals,
1010
safeParseBigInt,
11+
getTonAssetDecimals,
1112
} from '../helpers';
1213
import { jsonifyMap, jsonifyError } from '@mark/logger';
1314
import {
@@ -182,7 +183,8 @@ async function getTonNativeBalance(
182183
}
183184

184185
return safeParseBigInt(data.balance.toString());
185-
} catch {
186+
} catch (error) {
187+
console.log('getTonNativeBalance error', error);
186188
return 0n;
187189
}
188190
}
@@ -352,7 +354,6 @@ interface RebalanceRunState {
352354
export async function rebalanceTacUsdt(context: ProcessingContext): Promise<RebalanceAction[]> {
353355
const { logger, requestId, config, rebalance, prometheus } = context;
354356
const actions: RebalanceAction[] = [];
355-
356357
// Always check destination callbacks to ensure operations complete
357358
await executeTacCallbacks(context);
358359

@@ -1932,6 +1933,7 @@ const executeTacCallbacks = async (context: ProcessingContext): Promise<void> =>
19321933
});
19331934
continue;
19341935
}
1936+
const tonUSDTDecimals = getTonAssetDecimals(operation.tickerHash, config) ?? 6;
19351937

19361938
// Check TON native balance for gas
19371939
const tonNativeBalance = await getTonNativeBalance(tonWalletAddress, tonApiKey);
@@ -1948,6 +1950,14 @@ const executeTacCallbacks = async (context: ProcessingContext): Promise<void> =>
19481950

19491951
// Get actual USDT balance on TON
19501952
const actualUsdtBalance = await getTonJettonBalance(tonWalletAddress, jettonAddress, tonApiKey);
1953+
const actualUsdtBalance18 = convertTo18Decimals(actualUsdtBalance, tonUSDTDecimals);
1954+
logger.info('Ton Jetton Balance', {
1955+
tonWalletAddress,
1956+
jettonAddress,
1957+
decimals: 6,
1958+
actualUsdtBalance: actualUsdtBalance.toString(),
1959+
actualUsdtBalance18: actualUsdtBalance18.toString(),
1960+
});
19511961

19521962
// CRITICAL: Use operation-specific amount, NOT the full wallet balance
19531963
// This prevents mixing funds from multiple concurrent flows
@@ -1967,22 +1977,22 @@ const executeTacCallbacks = async (context: ProcessingContext): Promise<void> =>
19671977
const minExpectedAmount = calculateMinExpectedAmount(expectedAmount, slippageBps);
19681978

19691979
// Validate: TON wallet must have at least the minimum expected amount
1970-
if (actualUsdtBalance < minExpectedAmount) {
1980+
if (actualUsdtBalance18 < minExpectedAmount) {
19711981
// Not enough funds yet - Stargate might still be in transit or another flow took funds
19721982
logger.warn('Insufficient USDT on TON for this operation - waiting for Stargate delivery', {
19731983
...logContext,
19741984
expectedAmount: expectedAmount.toString(),
19751985
minExpectedAmount: minExpectedAmount.toString(),
1976-
actualUsdtBalance: actualUsdtBalance.toString(),
1977-
shortfall: (minExpectedAmount - actualUsdtBalance).toString(),
1986+
actualUsdtBalance18: actualUsdtBalance18.toString(),
1987+
shortfall: (minExpectedAmount - actualUsdtBalance18).toString(),
19781988
note: 'Will retry when funds arrive. If persists, check Stargate bridge status.',
19791989
});
19801990
continue;
19811991
}
19821992

19831993
// Calculate amount to bridge: min(expectedAmount, actualBalance)
19841994
// NEVER bridge more than the operation's expected amount
1985-
const amountToBridgeBigInt = actualUsdtBalance < expectedAmount ? actualUsdtBalance : expectedAmount;
1995+
const amountToBridgeBigInt = actualUsdtBalance18 < expectedAmount ? actualUsdtBalance18 : expectedAmount;
19861996
const amountToBridge = amountToBridgeBigInt.toString();
19871997

19881998
// Log if we're bridging less than expected (Stargate took fees)
@@ -1993,18 +2003,19 @@ const executeTacCallbacks = async (context: ProcessingContext): Promise<void> =>
19932003
recipient,
19942004
expectedAmount: expectedAmount.toString(),
19952005
minExpectedAmount: minExpectedAmount.toString(),
1996-
actualUsdtBalance: actualUsdtBalance.toString(),
2006+
actualUsdtBalance18: actualUsdtBalance18.toString(),
19972007
amountToBridge,
19982008
stargateFeesDeducted: tookFees,
19992009
note: tookFees
20002010
? `Bridging ${amountToBridge} (Stargate took ${expectedAmount - amountToBridgeBigInt} in fees)`
20012011
: 'Bridging expected amount',
20022012
});
20032013

2014+
const amountToBridgeNative = convertToNativeUnits(amountToBridgeBigInt, tonUSDTDecimals).toString();
20042015
const transactionLinker = await tacInnerAdapter.executeTacBridge(
20052016
tonMnemonic,
20062017
recipient,
2007-
amountToBridge,
2018+
amountToBridgeNative,
20082019
jettonAddress, // CRITICAL: Pass the TON jetton address for the asset to bridge
20092020
);
20102021

@@ -2030,7 +2041,7 @@ const executeTacCallbacks = async (context: ProcessingContext): Promise<void> =>
20302041
originChainId: Number(TON_LZ_CHAIN_ID),
20312042
destinationChainId: Number(TAC_CHAIN_ID),
20322043
tickerHash: operation.tickerHash,
2033-
amount: amountToBridge, // Use actual amount, not original
2044+
amount: amountToBridgeBigInt.toString(), // 18 decimals
20342045
slippage: 100,
20352046
// Use AWAITING_CALLBACK if we have transactionLinker (bridge submitted, awaiting completion)
20362047
// Use PENDING if no transactionLinker (bridge failed to submit, will retry)
@@ -2134,10 +2145,12 @@ const executeTacCallbacks = async (context: ProcessingContext): Promise<void> =>
21342145
});
21352146
continue;
21362147
}
2148+
const tonUSDTDecimals = getTonAssetDecimals(operation.tickerHash, config) ?? 6;
21372149

21382150
if (tonMnemonic && tonWalletAddress) {
21392151
// Get actual USDT balance on TON
21402152
const actualUsdtBalance = await getTonJettonBalance(tonWalletAddress, jettonAddress, tonApiKey);
2153+
const actualUsdtBalance18 = convertTo18Decimals(actualUsdtBalance, tonUSDTDecimals);
21412154

21422155
if (actualUsdtBalance === 0n) {
21432156
// No USDT on TON - bridge might have already succeeded!
@@ -2163,20 +2176,21 @@ const executeTacCallbacks = async (context: ProcessingContext): Promise<void> =>
21632176
const minExpectedAmount = calculateMinExpectedAmount(expectedAmount, slippageDbps);
21642177

21652178
// Validate: Must have at least minimum expected amount
2166-
if (actualUsdtBalance < minExpectedAmount) {
2179+
if (actualUsdtBalance18 < minExpectedAmount) {
21672180
logger.warn('Insufficient USDT on TON for this operation (retry) - waiting', {
21682181
...logContext,
21692182
expectedAmount: expectedAmount.toString(),
21702183
minExpectedAmount: minExpectedAmount.toString(),
2171-
actualUsdtBalance: actualUsdtBalance.toString(),
2184+
actualUsdtBalance18: actualUsdtBalance18.toString(),
21722185
note: 'Another flow may have taken funds or Stargate still in transit',
21732186
});
21742187
continue;
21752188
}
21762189

21772190
// Calculate amount: min(expectedAmount, actualBalance) - never more than expected
2178-
const amountToBridgeBigInt = actualUsdtBalance < expectedAmount ? actualUsdtBalance : expectedAmount;
2179-
const amountToBridge = amountToBridgeBigInt.toString();
2191+
const amountToBridgeBigInt =
2192+
actualUsdtBalance18 < expectedAmount ? actualUsdtBalance18 : expectedAmount;
2193+
const amountToBridge = convertToNativeUnits(amountToBridgeBigInt, tonUSDTDecimals).toString();
21802194

21812195
logger.info('Retrying TAC SDK bridge execution (no transactionLinker)', {
21822196
...logContext,

0 commit comments

Comments
 (0)