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
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"@across-protocol/constants": "^3.1.102",
"@across-protocol/contracts": "5.0.4",
"@across-protocol/sdk": "4.3.136",
"@across-protocol/sdk": "4.3.138",
"@arbitrum/sdk": "^4.0.2",
"@consensys/linea-sdk": "^0.3.0",
"@coral-xyz/anchor": "^0.31.1",
Expand All @@ -33,7 +33,6 @@
"@solana-program/compute-budget": "^0.8.0",
"@solana/kit": "^5.4.0",
"google-auth-library": "^8.5.1",
"axios": "^1.7.4",
"binance-api-node": "0.12.7",
"dotenv": "^16.3.1",
"ethers": "^5.7.2",
Expand Down
22 changes: 8 additions & 14 deletions scripts/fetchInventoryConfig.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { writeFile } from "node:fs/promises";
import { config } from "dotenv";
import axios from "axios";
import { GoogleAuth } from "google-auth-library";
import { Logger, waitForLogger, delay } from "../src/utils";
import { Logger, waitForLogger, delay, fetchWithTimeout } from "../src/utils";

const DEFAULT_ENVIRONMENT = "prod";
const AUTH_TIMEOUT_MS = 30000;
Expand All @@ -18,22 +17,21 @@ function withTimeout<T>(promise: Promise<T>, timeoutMs: number, operationName: s
]);
}

async function fetchWithRetry(
async function fetchConfigWithRetry(
url: string,
headers: Record<string, string>,
retries = 3,
delayMs = 1000
): Promise<string> {
for (let i = 0; i < retries; i++) {
try {
const response = await axios.get(url, { headers, responseType: "text", timeout: 30000 });
return response.data as string;
return await fetchWithTimeout<string>(url, {}, headers, 30000, "text");
} catch (error) {
if (i === retries - 1) {
throw error;
}
logger.warn({
at: "fetchInventoryConfig#fetchWithRetry",
at: "fetchInventoryConfig#fetchConfigWithRetry",
message: "Request failed, retrying",
attempt: `${i + 1}/${retries}`,
delayMs,
Expand Down Expand Up @@ -130,7 +128,7 @@ async function run(): Promise<number> {
label: spec.label,
configuramaFilePath,
});
const fileContent = await fetchWithRetry(url, headers);
const fileContent = await fetchConfigWithRetry(url, headers);
const jsonData = JSON.parse(fileContent);
await writeFile(localFilename, JSON.stringify(jsonData, null, 2));
logger.debug({
Expand Down Expand Up @@ -162,16 +160,12 @@ async function run(): Promise<number> {
}

function getErrorMessage(error: unknown): string {
if (axios.isAxiosError(error)) {
if (error.response?.status === 404) {
if (error instanceof Error) {
if (error.message.includes("HTTP 404")) {
return "File not found in Configurama";
} else if (error.response?.status === 401 || error.response?.status === 403) {
} else if (error.message.includes("HTTP 401") || error.message.includes("HTTP 403")) {
return "Authentication failed. Ensure ADC is configured to call the Configurama API.";
} else {
return `Configurama API error: ${error.response?.status} - ${error.message}`;
}
}
if (error instanceof Error) {
return error.message;
}
return String(error);
Expand Down
35 changes: 9 additions & 26 deletions scripts/simulateFill.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import axios from "axios";
import minimist from "minimist";
import { config } from "dotenv";
import { LogDescription } from "@ethersproject/abi";
Expand All @@ -11,6 +10,7 @@ import {
getProvider,
isDefined,
populateV3Relay,
postWithTimeout,
toAddressType,
chainIsEvm,
getBlockForTimestamp,
Expand Down Expand Up @@ -170,32 +170,22 @@ async function createTenderlySimulation(
public: true, // Make simulation publicly accessible
};

const headers = {
"X-Access-Key": tenderlyAccessKey,
};

try {
const response = await axios.post(tenderlyUrl, simulationPayload, {
headers: {
"X-Access-Key": tenderlyAccessKey,
"Content-Type": "application/json",
},
});
const response = await postWithTimeout<{ simulation: { id: string } }>(tenderlyUrl, simulationPayload, {}, headers);

const simulationId = response.data.simulation.id;
const simulationId = response.simulation.id;

console.log(`\nDebug: Simulation created with ID: ${simulationId}`);

// Enable sharing by calling the share endpoint
const shareUrl = `https://api.tenderly.co/api/v1/account/${tenderlyUser}/project/${tenderlyProject}/simulations/${simulationId}/share`;

try {
await axios.post(
shareUrl,
{}, // Empty body
{
headers: {
"X-Access-Key": tenderlyAccessKey,
"Content-Type": "application/json",
},
}
);
await postWithTimeout(shareUrl, {}, {}, headers);

console.log("Debug: Share enabled for simulation");

Expand All @@ -207,19 +197,12 @@ async function createTenderlySimulation(
} catch (shareError) {
// If share endpoint fails, fall back to the regular dashboard URL
console.warn("Could not enable sharing, using dashboard URL instead");
if (axios.isAxiosError(shareError)) {
console.warn("Share endpoint error:", shareError.response?.status, shareError.response?.data);
}
console.warn("Share endpoint error:", (shareError as Error).message);
}

// Fallback to dashboard URL
return `https://dashboard.tenderly.co/${tenderlyUser}/${tenderlyProject}/simulator/${simulationId}`;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(
`Tenderly simulation failed: ${error.response?.status} - ${JSON.stringify(error.response?.data)}`
);
}
throw error instanceof Error ? error : new Error(String(error));
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/clients/AcrossAPIClient.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import _ from "lodash";
import axios, { AxiosError } from "axios";
import {
bnZero,
winston,
BigNumber,
dedupArray,
fetchWithTimeout,
getCurrentTime,
TOKEN_SYMBOLS_MAP,
CHAIN_IDs,
Expand Down Expand Up @@ -135,8 +135,8 @@ export class AcrossApiClient {
const params = { l1Tokens: l1Tokens.join(",") };
let liquidReserves: BigNumber[] = [];
try {
const result = await axios(url, { timeout, params });
if (!result?.data) {
const result = await fetchWithTimeout<Record<string, string>>(url, params, {}, timeout);
if (!result) {
this.logger.error({
at: "AcrossAPIClient",
message: `Invalid response from /${path}, expected maxDeposit field.`,
Expand All @@ -145,9 +145,9 @@ export class AcrossApiClient {
result,
});
}
liquidReserves = l1Tokens.map((l1Token) => BigNumber.from(result.data[l1Token.toEvmAddress()] ?? bnZero));
liquidReserves = l1Tokens.map((l1Token) => BigNumber.from(result[l1Token.toEvmAddress()] ?? bnZero));
} catch (err) {
const msg = _.get(err, "response.data", _.get(err, "response.statusText", (err as AxiosError).message));
const msg = (err as Error).message;
this.logger.warn({ at: "AcrossAPIClient", message: `Failed to get ${path},`, url, params, msg });
return l1Tokens.map(() => bnZero);
}
Expand Down
18 changes: 7 additions & 11 deletions src/clients/AcrossApiBaseClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axios, { AxiosError } from "axios";
import { fetchWithTimeout } from "../utils/SDKUtils";
import winston from "winston";

/**
Expand Down Expand Up @@ -34,18 +34,14 @@ export abstract class BaseAcrossApiClient {

protected async _get<T>(endpoint: string, params: Record<string, unknown>): Promise<T | undefined> {
try {
const config: { timeout: number; params: Record<string, unknown>; headers?: Record<string, string> } = {
timeout: this.apiResponseTimeout,
params,
};

const headers: Record<string, string> = {};
if (this.apiKey) {
config.headers = { Authorization: `Bearer ${this.apiKey}` };
headers.Authorization = `Bearer ${this.apiKey}`;
}

const response = await axios.get<T>(`${this.urlBase}/${endpoint}`, config);
const result = await fetchWithTimeout<T>(`${this.urlBase}/${endpoint}`, params, headers, this.apiResponseTimeout);

if (!response?.data) {
if (!result) {
this.logger.warn({
at: this.logContext,
message: `Invalid response from ${this.urlBase}`,
Expand All @@ -54,14 +50,14 @@ export abstract class BaseAcrossApiClient {
});
return;
}
return response.data;
return result;
} catch (err) {
this.logger.warn({
at: this.logContext,
message: `Failed to get from ${this.urlBase}`,
endpoint,
params,
error: (err as AxiosError).message,
error: (err as Error).message,
});
return;
}
Expand Down
14 changes: 7 additions & 7 deletions src/finalizer/utils/helios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import {
groupObjectCountsByProp,
isEVMSpokePoolClient,
assert,
fetchWithTimeout,
postWithTimeout,
} from "../../utils";
import { spreadEventWithBlockNumber } from "../../utils/EventUtils";
import { FinalizerPromise, CrossChainMessage } from "../types";
import axios from "axios";
import UNIVERSAL_SPOKE_ABI from "../../common/abi/Universal_SpokePool.json";
import { RelayedCallDataEvent, StoredCallDataEvent } from "../../interfaces/Universal";
import { ApiProofRequest, ProofOutputs, ProofStateResponse, SP1HeliosProofData } from "../../interfaces/ZkApi";
Expand Down Expand Up @@ -343,21 +344,20 @@ async function enrichHeliosActions(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let getError: any = null;
try {
const response = await axios.get<ProofStateResponse>(getProofUrl);
proofState = response.data;
proofState = await fetchWithTimeout<ProofStateResponse>(getProofUrl);
logger.debug({ ...logContext, message: "Proof state received", proofId, status: proofState.status });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
getError = error;
}

// Axios error. Handle based on whether was a NOTFOUND or another error
// Handle fetch error based on whether it was a NOTFOUND or another error
if (getError) {
const isNotFoundError = axios.isAxiosError(getError) && getError.response?.status === 404;
const isNotFoundError = getError instanceof Error && getError.message.includes("HTTP 404");
if (isNotFoundError) {
// NOTFOUND error -> Request proof
logger.debug({ ...logContext, message: "Proof not found (404), requesting...", proofId });
await axios.post(`${apiBaseUrl}/v1/api/proofs`, apiRequest);
await postWithTimeout(`${apiBaseUrl}/v1/api/proofs`, apiRequest);
logger.debug({ ...logContext, message: "Proof requested successfully.", proofId });
continue;
} else {
Expand Down Expand Up @@ -386,7 +386,7 @@ async function enrichHeliosActions(
errorMessage: proofState.error_message,
});

await axios.post(`${apiBaseUrl}/v1/api/proofs`, apiRequest);
await postWithTimeout(`${apiBaseUrl}/v1/api/proofs`, apiRequest);
logger.debug({ ...logContext, message: "Errored proof requested again successfully.", proofId });
break;
}
Expand Down
14 changes: 6 additions & 8 deletions src/finalizer/utils/scroll.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { utils as sdkUtils } from "@across-protocol/sdk";
import axios from "axios";
import { HubPoolClient, SpokePoolClient } from "../../clients";
import { CONTRACT_ADDRESSES } from "../../common";
import {
Expand All @@ -9,6 +8,7 @@ import {
Multicall2Call,
winston,
convertFromWei,
fetchWithTimeout,
getTokenInfo,
assert,
isEVMSpokePoolClient,
Expand Down Expand Up @@ -97,7 +97,7 @@ async function findOutstandingClaims(targetAddress: string): Promise<ScrollClaim
do {
requestResponse =
(
await axios.get<{
await fetchWithTimeout<{
data: {
results: {
claim_info: ScrollClaimInfo;
Expand All @@ -106,13 +106,11 @@ async function findOutstandingClaims(targetAddress: string): Promise<ScrollClaim
}[];
};
}>(apiUrl, {
params: {
address: targetAddress,
page_size: MAX_PAGE_SIZE,
page: currentPage,
},
address: targetAddress,
page_size: MAX_PAGE_SIZE,
page: currentPage,
})
).data.data?.results ?? [];
).data?.results ?? [];
claimList.push(
...requestResponse
.filter(({ claim_info }) => claim_info?.claimable)
Expand Down
Loading
Loading