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
4 changes: 4 additions & 0 deletions ops/mainnet/prod/core/config.tf
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,10 @@ locals {
providers = [
"https://api.trongrid.io?apiKey=${var.trongrid_api_key}"
]
minBandwidthOnRelayer = 0
minEnergyOnRelayer = 0
minBandwidthOnGateway = 0
minEnergyOnGateway = 0
},
"100" = {
providers = [
Expand Down
4 changes: 4 additions & 0 deletions ops/mainnet/staging/core/config.tf
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ locals {
providers = [
"https://api.trongrid.io?apiKey=${var.trongrid_api_key}"
]
minBandwidthOnRelayer = 0
minEnergyOnRelayer = 0
minBandwidthOnGateway = 0
minEnergyOnGateway = 0
}
}
betterUptime = {
Expand Down
2 changes: 0 additions & 2 deletions packages/adapters/chainservice/src/mockable.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { axiosGet as _axiosGet } from '@chimera-monorepo/utils';
import { TronWeb as _tronWeb } from 'tronweb';

export const axiosGet = _axiosGet;
export const TronWeb = _tronWeb;
26 changes: 4 additions & 22 deletions packages/adapters/chainservice/src/shared/rpc/tron/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import {
} from '../../types';
import { SyncProvider } from '../eth';
import { UnpredictableGasLimit, TransactionReadError } from '../../errors';
import { TronWeb } from '../../../mockable';
import { Interface } from 'ethers/lib/utils';
import fetch from 'node-fetch';
import { DefaultTronWebFactory, TronWebFactory, TronWebInstance } from '@chimera-monorepo/utils';

interface ContractFunctionParameter {
type: string;
Expand All @@ -26,24 +26,8 @@ interface TronLog {
data: string;
}

type TronWebInstance = InstanceType<typeof TronWeb>;

const DEFAULT_ADDRESS = '410000000000000000000000000000000000000000';

export interface TronWebFactory {
create(config: { fullHost: string; apiKey?: string }): TronWebInstance;
}

class DefaultTronWebFactory implements TronWebFactory {
create(config: { fullHost: string; apiKey?: string }): TronWebInstance {
const tronWebConfig: any = { fullHost: config.fullHost };
if (config.apiKey) {
tronWebConfig.headers = { "TRON-PRO-API-KEY": config.apiKey };
}
return new TronWeb(tronWebConfig);
}
}

// For simple parameters, decode and convert to TronWeb format
function decodeSimpleParameters(data: string, funcSig: string, value?: string): ContractFunctionParameter[] {
try {
Expand Down Expand Up @@ -74,6 +58,7 @@ function decodeSimpleParameters(data: string, funcSig: string, value?: string):
return [];
}
}

class TronWeb3Signer implements ISigner {
public readonly tronWeb: TronWebInstance;

Expand Down Expand Up @@ -328,16 +313,13 @@ export class TronSyncProvider extends SyncProvider {
debugLogging = false,
private readonly tronWebFactory: TronWebFactory = new DefaultTronWebFactory(),
) {
// Extract API key from URL if present
const urlObj = new URL(url);
const apiKey = urlObj.searchParams.get('apiKey');

// Remove API key from URL to get clean fullHost
const urlObj = new URL(url);
urlObj.searchParams.delete('apiKey');
const cleanUrl = urlObj.toString();

super(cleanUrl, domain, stallTimeout, debugLogging);
this.tronWeb = this.tronWebFactory.create({ fullHost: cleanUrl, apiKey: apiKey || undefined });
this.tronWeb = this.tronWebFactory.create(url);
}

public async sync(): Promise<void> {
Expand Down
15 changes: 5 additions & 10 deletions packages/adapters/chainservice/test/unit/shared/rpc/tron.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect } from 'chai';
import { stub, SinonStub, restore } from 'sinon';
import { TronSyncProvider, TronWebFactory } from '../../../../src/shared/rpc/tron/provider';
import { TronSyncProvider } from '../../../../src/shared/rpc/tron';
import { TronWebFactory } from '@chimera-monorepo/utils';
import { TronWeb } from 'tronweb';
import { BigNumber, Bytes } from 'ethers';
import { ISigner, ISignerApi } from '../../../../src';
Expand Down Expand Up @@ -125,7 +126,7 @@ describe('TronSyncProvider', () => {

// Create a mock factory that returns our mock TronWeb
mockTronWebFactory = {
create: (config: { fullHost: string; apiKey?: string }) => mockTronWeb as unknown as InstanceType<typeof TronWeb>
create: (url: string) => mockTronWeb as unknown as InstanceType<typeof TronWeb>
};

// Create provider with mock factory
Expand Down Expand Up @@ -186,10 +187,7 @@ describe('TronSyncProvider', () => {
);

expect(createStub.calledOnce).to.be.true;
expect(createStub.firstCall.args[0]).to.deep.equal({
fullHost: 'http://tron.test/',
apiKey: testApiKey
});
expect(createStub.firstCall.args[0]).to.deep.equal('http://tron.test?apiKey=test-api-key-123');
});

it('should work without API key in URL', () => {
Expand All @@ -204,10 +202,7 @@ describe('TronSyncProvider', () => {
);

expect(createStub.calledOnce).to.be.true;
expect(createStub.firstCall.args[0]).to.deep.equal({
fullHost: 'http://tron.test/',
apiKey: undefined
});
expect(createStub.firstCall.args[0]).to.deep.equal('http://tron.test');
});
});

Expand Down
1 change: 1 addition & 0 deletions packages/adapters/database/test/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ describe('Database Adapter:Client', () => {

await sleep(100);
const from = new Date();
await sleep(100);

event.transactionHash = mkBytes32('0x3');
await saveRewardClaimedEvent(event);
Expand Down
2 changes: 1 addition & 1 deletion packages/adapters/database/test/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const createMockDatabase = (): Database => {
getCheckPoint: stub().resolves(0),
getMessageQueues: stub().resolves([]),
getMessageQueueContents: stub().resolves(new Map()),
getAllQueuedSettlements: stub().resolves({}),
getAllQueuedSettlements: stub().resolves(new Map()),
getOriginIntentsByStatus: stub().resolves([]),
getDestinationIntentsByStatus: stub().resolves([]),
getMessagesByIntentIds: stub().resolves([]),
Expand Down
5 changes: 4 additions & 1 deletion packages/agents/monitor/.nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"src/lambda.ts",
"src/helpers/alerts.ts",
"src/types/errors.ts",
"src/config.ts"
"src/config.ts",
"src/context.ts",
"src/mockable.ts",
"src/run.ts"
],
"all": true,
"check-coverage": true
Expand Down
29 changes: 3 additions & 26 deletions packages/agents/monitor/src/checklist/gas.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createLoggingContext } from '@chimera-monorepo/utils';
import { createLoggingContext, GasType } from '@chimera-monorepo/utils';
import { getContext } from '../context';
import { CheckGasResponse, Severity } from '../types';
import { BigNumber, utils } from 'ethers';
import axios from 'axios';
import { resolveAlerts, sendAlerts } from '../mockable';
import { fetchRelayerData } from '../helpers';

export const checkGas = async (shouldAlert = true): Promise<CheckGasResponse> => {
const {
Expand Down Expand Up @@ -62,19 +62,9 @@ export const checkGas = async (shouldAlert = true): Promise<CheckGasResponse> =>
? await chainreader.getBalance(+domainId, tokenonmicsGatewayAddress, native?.address)
: undefined;

logger.debug(`Checking chain gas: ${domainId}`, requestContext, methodContext, {
domainId,
relayerAddress,
relayerGas,
gatewayAddress,
gatewayGas,
tokenomicsGatewayGas,
relayerThresholdValue,
gatewayThresholdValue,
});

chainGas.push({
domain: domainId,
gasType: GasType.Gas,
relayerAddress,
belowRelayerThreshold: relayerGas ? BigNumber.from(relayerGas).lt(relayerThreshold) : false,
relayerGas,
Expand Down Expand Up @@ -199,16 +189,3 @@ export const checkGas = async (shouldAlert = true): Promise<CheckGasResponse> =>

return chainGas;
};

/**
* Fetch address from the given relayer URL.
*/
async function fetchRelayerData(relayerUrl: string): Promise<string | undefined> {
try {
const response = await axios.get(`${relayerUrl}/address`);
return response.data;
} catch (error) {
console.error(`Error fetching address from ${relayerUrl}:`, error);
return undefined;
}
}
5 changes: 4 additions & 1 deletion packages/agents/monitor/src/checklist/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { getContext } from '../context';
import { checkSpokeBalance } from './spoke';
import { checkTokenomicsExportLatency, checkTokenomicsExportStatus } from './tokenomics';
import { checkSolanaPipelineStatus } from './solana';
import { checkTronGas, checkTronPipelineStatus } from './tron';

export const runChecks = async (_requestContext?: RequestContext) => {
const { methodContext, requestContext } = createLoggingContext(runChecks.name, _requestContext);
Expand All @@ -41,11 +42,13 @@ export const runChecks = async (_requestContext?: RequestContext) => {
checkTokenomicsExportStatus,
checkTokenomicsExportLatency,
checkSolanaPipelineStatus,
checkTronGas,
checkTronPipelineStatus,
checkInvoices,
checkMessageStatus,
checkChains,
checkGas,
checkSpokeBalance,
checkChains,
checkRpcs,
];

Expand Down
5 changes: 3 additions & 2 deletions packages/agents/monitor/src/checklist/queue/deposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { getContext } from '../../context';
import { Severity } from '../../types';
import { resolveAlerts, sendAlerts } from '../../mockable';
import { getSupportedDomains } from '../../helpers';

export const checkDepositQueueCount = async (): Promise<Map<string, number>> => {
const {
Expand All @@ -16,7 +17,7 @@ export const checkDepositQueueCount = async (): Promise<Map<string, number>> =>
} = getContext();
const { requestContext, methodContext } = createLoggingContext(checkDepositQueueCount.name);

const domains = Object.keys(config.chains).filter((domain) => config.chains[domain].network === 'evm');
const domains = getSupportedDomains(config.chains);
const enqueuedDepositsByDomain = await database.getAllEnqueuedDeposits(domains);

const queueCountByKey: Map<string, number> = new Map();
Expand Down Expand Up @@ -85,7 +86,7 @@ export const checkDepositQueueLatency = async (): Promise<Map<string, number>> =
} = getContext();
const { requestContext, methodContext } = createLoggingContext(checkDepositQueueLatency.name);

const domains = Object.keys(config.chains).filter((domain) => config.chains[domain].network === 'evm');
const domains = getSupportedDomains(config.chains);
logger.debug('Method start', requestContext, methodContext, {
domains,
hubDomain: config.hub.domain,
Expand Down
9 changes: 5 additions & 4 deletions packages/agents/monitor/src/checklist/queue/intent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { QueueType, createLoggingContext, getNtpTimeSeconds } from '@chimera-mon
import { getContext } from '../../context';
import { Severity } from '../../types';
import { resolveAlerts, sendAlerts } from '../../mockable';
import { getSupportedDomains } from '../../helpers';

export const checkFillQueueCount = async (): Promise<Map<string, number>> => {
const {
Expand All @@ -11,7 +12,7 @@ export const checkFillQueueCount = async (): Promise<Map<string, number>> => {
} = getContext();
const { requestContext, methodContext } = createLoggingContext(checkFillQueueCount.name);

const domains = Object.keys(config.chains).filter((domain) => config.chains[domain].network === 'evm');
const domains = getSupportedDomains(config.chains);
const intentsByDomain = await database.getMessageQueueContents(QueueType.Fill, domains);
const countsByDomain = new Map<string, number>(
domains.map((domain) => [domain, intentsByDomain.get(domain)?.length ?? 0]),
Expand Down Expand Up @@ -62,7 +63,7 @@ export const checkFillQueueLatency = async (): Promise<Map<string, number>> => {
} = getContext();
const { requestContext, methodContext } = createLoggingContext(checkFillQueueLatency.name);

const domains = Object.keys(config.chains).filter((domain) => config.chains[domain].network === 'evm');
const domains = getSupportedDomains(config.chains);
const intentsByDomain = await database.getMessageQueueContents(QueueType.Fill, domains);

const latencyByDomain = new Map<string, number>();
Expand Down Expand Up @@ -133,7 +134,7 @@ export const checkIntentQueueCount = async (): Promise<Map<string, number>> => {
} = getContext();
const { requestContext, methodContext } = createLoggingContext(checkIntentQueueCount.name);

const domains = Object.keys(config.chains).filter((domain) => config.chains[domain].network === 'evm');
const domains = getSupportedDomains(config.chains);
const intentsByDomain = await database.getMessageQueueContents(QueueType.Intent, domains);
const countsByDomain = new Map<string, number>(
domains.map((domain) => [domain, intentsByDomain.get(domain)?.length ?? 0]),
Expand Down Expand Up @@ -184,7 +185,7 @@ export const checkIntentQueueLatency = async (): Promise<Map<string, number>> =>
} = getContext();
const { requestContext, methodContext } = createLoggingContext(checkIntentQueueLatency.name);

const domains = Object.keys(config.chains).filter((domain) => config.chains[domain].network === 'evm');
const domains = getSupportedDomains(config.chains);
const intentsByDomain = await database.getMessageQueueContents(QueueType.Intent, domains);

const latencyByDomain = new Map<string, number>();
Expand Down
9 changes: 6 additions & 3 deletions packages/agents/monitor/src/checklist/queue/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ export const getIntentStatus = async (
): Promise<IntentMessageSummary> => {
const {
config,
adapters: { subgraph },
adapters: { subgraph, database },
} = getContext();

// Retrieve intent records from subgraph.
// Check if originDomain is Tron - if so, query from database instead of subgraph
const isTronOrigin = config.chains[originDomain]?.network === 'tvm';

// Retrieve intent records from subgraph and db.
const [originIntent, hubIntent, ...destinationIntents] = await Promise.all([
subgraph.getOriginIntentById(originDomain, intentId),
isTronOrigin ? database.getOriginIntentsById(intentId) : subgraph.getOriginIntentById(originDomain, intentId),
subgraph.getHubIntentById(config.hub.domain, intentId),
...destinationDomains.map((domain) => subgraph.getDestinationIntentById(domain, intentId)),
]);
Expand Down
12 changes: 9 additions & 3 deletions packages/agents/monitor/src/checklist/queue/settlement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { BigNumber, utils } from 'ethers';
import { getContext } from '../../context';
import { Severity } from '../../types';
import { resolveAlerts, sendAlerts } from '../../mockable';
import { getSupportedDomains } from '../../helpers';

export const checkSettlementQueueStatusCount = async (): Promise<Map<string, Map<string, number>>> => {
const {
Expand All @@ -12,11 +13,10 @@ export const checkSettlementQueueStatusCount = async (): Promise<Map<string, Map
} = getContext();
const { requestContext, methodContext } = createLoggingContext(checkSettlementQueueStatusCount.name);

const domains = Object.keys(config.chains).filter((domain) => config.chains[domain].network === 'evm');
const domains = getSupportedDomains(config.chains);
logger.debug('Method start', requestContext, methodContext, {
domains,
hubDomain: config.hub.domain,
assets: config.chains.assets,
});

// Get all of the queued settlements
Expand All @@ -25,6 +25,9 @@ export const checkSettlementQueueStatusCount = async (): Promise<Map<string, Map
await Promise.all(
[...queuedSettlements].map(async (_record) => {
const [settlementDomain, settlements] = _record;
if (!domains.includes(settlementDomain)) {
return;
}
const statusCounts = statusCountByTicker.get(settlementDomain) || new Map<string, number>();
settlements.forEach((settlement) => {
// Increment the status count
Expand Down Expand Up @@ -151,7 +154,7 @@ export const checkSettlementQueueLatency = async (): Promise<Map<string, number>
} = getContext();
const { requestContext, methodContext } = createLoggingContext(checkSettlementQueueLatency.name);

const domains = Object.keys(config.chains).filter((domain) => config.chains[domain].network === 'evm');
const domains = getSupportedDomains(config.chains);
logger.debug('Method start', requestContext, methodContext, {
domains,
hubDomain: config.hub.domain,
Expand Down Expand Up @@ -187,6 +190,9 @@ export const checkSettlementQueueLatency = async (): Promise<Map<string, number>
await Promise.all(
[...queuedSettlements].map(async (_record) => {
const [settlementDomain, settlements] = _record;
if (!domains.includes(settlementDomain)) {
return;
}
settlements.forEach((settlement) => {
// Identify latency by tickerhash
if (settlement.status == 'DISPATCHED') return; // Only check latency for unsettled settlements
Expand Down
Loading
Loading