Skip to content

Commit 87150c9

Browse files
authored
Merge pull request #2506 from pyth-network/more-network-metrics
feat(apps/price_pusher): add support for aptos and sui metrics
2 parents 5cb4f2e + c1bce15 commit 87150c9

9 files changed

+490
-83
lines changed

apps/price_pusher/grafana-dashboard.sample.json

+172-35
Large diffs are not rendered by default.

apps/price_pusher/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pythnetwork/price-pusher",
3-
"version": "9.1.2",
3+
"version": "9.1.3",
44
"description": "Pyth Price Pusher",
55
"homepage": "https://pyth.network",
66
"main": "lib/index.js",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { AptosClient } from "aptos";
2+
import {
3+
BaseBalanceTracker,
4+
BaseBalanceTrackerConfig,
5+
IBalanceTracker,
6+
} from "../interface";
7+
import { DurationInSeconds } from "../utils";
8+
import { PricePusherMetrics } from "../metrics";
9+
import { Logger } from "pino";
10+
11+
/**
12+
* Aptos-specific configuration for balance tracker
13+
*/
14+
export interface AptosBalanceTrackerConfig extends BaseBalanceTrackerConfig {
15+
/** Aptos node endpoint URL */
16+
endpoint: string;
17+
/** Aptos account address */
18+
address: string;
19+
/** Optional decimal places for APT token (default: 8) */
20+
decimals?: number;
21+
}
22+
23+
/**
24+
* Aptos-specific implementation of the balance tracker
25+
*/
26+
export class AptosBalanceTracker extends BaseBalanceTracker {
27+
private client: AptosClient;
28+
private aptosAddress: string;
29+
private decimals: number;
30+
31+
constructor(config: AptosBalanceTrackerConfig) {
32+
super({
33+
...config,
34+
logger: config.logger.child({ module: "AptosBalanceTracker" }),
35+
});
36+
37+
this.client = new AptosClient(config.endpoint);
38+
this.aptosAddress = config.address;
39+
// APT has 8 decimal places by default
40+
this.decimals = config.decimals ?? 8;
41+
}
42+
43+
/**
44+
* Aptos-specific implementation of balance update
45+
* Fetches the native APT balance for the configured address
46+
*/
47+
protected async updateBalance(): Promise<void> {
48+
try {
49+
// Get account resource to check the balance
50+
const accountResource = await this.client.getAccountResource(
51+
this.aptosAddress,
52+
"0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
53+
);
54+
55+
// Extract the balance value from the account resource
56+
const rawBalance = (accountResource.data as any).coin.value;
57+
58+
// Convert the balance to a bigint
59+
const balance = BigInt(rawBalance);
60+
61+
// Calculate the normalized balance for display
62+
const normalizedBalance = Number(balance) / Math.pow(10, this.decimals);
63+
64+
// Update metrics with the new balance
65+
this.metrics.updateWalletBalance(
66+
this.address,
67+
this.network,
68+
normalizedBalance,
69+
);
70+
71+
this.logger.debug(
72+
`Updated Aptos wallet balance: ${this.address} = ${normalizedBalance.toString()} APT (raw: ${balance.toString()})`,
73+
);
74+
} catch (error) {
75+
this.logger.error(
76+
{ error },
77+
"Error fetching Aptos wallet balance for metrics",
78+
);
79+
}
80+
}
81+
}
82+
83+
/**
84+
* Parameters for creating an Aptos balance tracker
85+
*/
86+
export interface CreateAptosBalanceTrackerParams {
87+
endpoint: string;
88+
address: string;
89+
network: string;
90+
updateInterval: DurationInSeconds;
91+
metrics: PricePusherMetrics;
92+
logger: Logger;
93+
decimals?: number;
94+
}
95+
96+
/**
97+
* Factory function to create a balance tracker for Aptos chain
98+
*/
99+
export function createAptosBalanceTracker(
100+
params: CreateAptosBalanceTrackerParams,
101+
): IBalanceTracker {
102+
return new AptosBalanceTracker({
103+
endpoint: params.endpoint,
104+
address: params.address,
105+
network: params.network,
106+
updateInterval: params.updateInterval,
107+
metrics: params.metrics,
108+
logger: params.logger,
109+
decimals: params.decimals,
110+
});
111+
}

apps/price_pusher/src/aptos/command.ts

+34-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import {
1313
import { AptosAccount } from "aptos";
1414
import pino from "pino";
1515
import { filterInvalidPriceItems } from "../utils";
16+
import { PricePusherMetrics } from "../metrics";
17+
import { createAptosBalanceTracker } from "./balance-tracker";
18+
1619
export default {
1720
command: "aptos",
1821
describe: "run price pusher for aptos",
@@ -40,6 +43,8 @@ export default {
4043
...options.pushingFrequency,
4144
...options.logLevel,
4245
...options.controllerLogLevel,
46+
...options.enableMetrics,
47+
...options.metricsPort,
4348
},
4449
handler: async function (argv: any) {
4550
// FIXME: type checks for this
@@ -54,13 +59,23 @@ export default {
5459
overrideGasPriceMultiplier,
5560
logLevel,
5661
controllerLogLevel,
62+
enableMetrics,
63+
metricsPort,
5764
} = argv;
5865

5966
const logger = pino({ level: logLevel });
6067

6168
const priceConfigs = readPriceConfigFile(priceConfigFile);
6269
const hermesClient = new HermesClient(priceServiceEndpoint);
6370

71+
// Initialize metrics if enabled
72+
let metrics: PricePusherMetrics | undefined;
73+
if (enableMetrics) {
74+
metrics = new PricePusherMetrics(logger.child({ module: "Metrics" }));
75+
metrics.start(metricsPort);
76+
logger.info(`Metrics server started on port ${metricsPort}`);
77+
}
78+
6479
const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
6580
const account = AptosAccount.fromDerivePath(
6681
APTOS_ACCOUNT_HD_PATH,
@@ -113,9 +128,27 @@ export default {
113128
aptosListener,
114129
aptosPusher,
115130
logger.child({ module: "Controller" }, { level: controllerLogLevel }),
116-
{ pushingFrequency },
131+
{
132+
pushingFrequency,
133+
metrics,
134+
},
117135
);
118136

137+
// Create and start the balance tracker if metrics are enabled
138+
if (metrics) {
139+
const balanceTracker = createAptosBalanceTracker({
140+
address: account.address().toString(),
141+
endpoint,
142+
network: "aptos",
143+
updateInterval: pushingFrequency,
144+
metrics,
145+
logger: logger.child({ module: "AptosBalanceTracker" }),
146+
});
147+
148+
// Start the balance tracker
149+
await balanceTracker.start();
150+
}
151+
119152
controller.start();
120153
},
121154
};

apps/price_pusher/src/balance-tracker.ts

-38
This file was deleted.

apps/price_pusher/src/evm/balance-tracker.ts

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import { SuperWalletClient } from "./super-wallet";
2-
import { BaseBalanceTracker, BaseBalanceTrackerConfig } from "../interface";
2+
import {
3+
BaseBalanceTracker,
4+
BaseBalanceTrackerConfig,
5+
IBalanceTracker,
6+
} from "../interface";
7+
import { DurationInSeconds } from "../utils";
8+
import { PricePusherMetrics } from "../metrics";
9+
import { Logger } from "pino";
310

411
/**
512
* EVM-specific configuration for balance tracker
@@ -49,3 +56,31 @@ export class EvmBalanceTracker extends BaseBalanceTracker {
4956
}
5057
}
5158
}
59+
60+
/**
61+
* Parameters for creating an EVM balance tracker
62+
*/
63+
export interface CreateEvmBalanceTrackerParams {
64+
client: SuperWalletClient;
65+
address: `0x${string}`;
66+
network: string;
67+
updateInterval: DurationInSeconds;
68+
metrics: PricePusherMetrics;
69+
logger: Logger;
70+
}
71+
72+
/**
73+
* Factory function to create a balance tracker for EVM chains
74+
*/
75+
export function createEvmBalanceTracker(
76+
params: CreateEvmBalanceTrackerParams,
77+
): IBalanceTracker {
78+
return new EvmBalanceTracker({
79+
client: params.client,
80+
address: params.address,
81+
network: params.network,
82+
updateInterval: params.updateInterval,
83+
metrics: params.metrics,
84+
logger: params.logger,
85+
});
86+
}

apps/price_pusher/src/evm/command.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { createClient } from "./super-wallet";
1212
import { createPythContract } from "./pyth-contract";
1313
import { isWsEndpoint, filterInvalidPriceItems } from "../utils";
1414
import { PricePusherMetrics } from "../metrics";
15-
import { createEvmBalanceTracker } from "../balance-tracker";
15+
import { createEvmBalanceTracker } from "./balance-tracker";
1616

1717
export default {
1818
command: "evm",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { SuiClient } from "@mysten/sui/client";
2+
import {
3+
BaseBalanceTracker,
4+
BaseBalanceTrackerConfig,
5+
IBalanceTracker,
6+
} from "../interface";
7+
import { DurationInSeconds } from "../utils";
8+
import { PricePusherMetrics } from "../metrics";
9+
import { Logger } from "pino";
10+
11+
/**
12+
* Sui-specific configuration for balance tracker
13+
*/
14+
export interface SuiBalanceTrackerConfig extends BaseBalanceTrackerConfig {
15+
/** Sui client instance */
16+
client: SuiClient;
17+
}
18+
19+
/**
20+
* Sui-specific implementation of the balance tracker
21+
*/
22+
export class SuiBalanceTracker extends BaseBalanceTracker {
23+
private client: SuiClient;
24+
25+
constructor(config: SuiBalanceTrackerConfig) {
26+
super({
27+
...config,
28+
logger: config.logger.child({ module: "SuiBalanceTracker" }),
29+
});
30+
31+
this.client = config.client;
32+
}
33+
34+
/**
35+
* Sui-specific implementation of balance update
36+
*/
37+
protected async updateBalance(): Promise<void> {
38+
try {
39+
// Get all coins owned by the address
40+
const { data: coins } = await this.client.getCoins({
41+
owner: this.address,
42+
});
43+
44+
// Sum up all coin balances
45+
const totalBalance = coins.reduce((acc, coin) => {
46+
return acc + BigInt(coin.balance);
47+
}, BigInt(0));
48+
49+
// Convert to a normalized number for reporting (SUI has 9 decimals)
50+
const normalizedBalance = Number(totalBalance) / 1e9;
51+
52+
this.metrics.updateWalletBalance(
53+
this.address,
54+
this.network,
55+
normalizedBalance,
56+
);
57+
58+
this.logger.debug(
59+
`Updated Sui wallet balance: ${this.address} = ${normalizedBalance} SUI`,
60+
);
61+
} catch (error) {
62+
this.logger.error(
63+
{ error },
64+
"Error fetching Sui wallet balance for metrics",
65+
);
66+
}
67+
}
68+
}
69+
70+
/**
71+
* Parameters for creating a Sui balance tracker
72+
*/
73+
export interface CreateSuiBalanceTrackerParams {
74+
client: SuiClient;
75+
address: string;
76+
network: string;
77+
updateInterval: DurationInSeconds;
78+
metrics: PricePusherMetrics;
79+
logger: Logger;
80+
}
81+
82+
/**
83+
* Factory function to create a balance tracker for Sui chain
84+
*/
85+
export function createSuiBalanceTracker(
86+
params: CreateSuiBalanceTrackerParams,
87+
): IBalanceTracker {
88+
return new SuiBalanceTracker({
89+
client: params.client,
90+
address: params.address,
91+
network: params.network,
92+
updateInterval: params.updateInterval,
93+
metrics: params.metrics,
94+
logger: params.logger,
95+
});
96+
}

0 commit comments

Comments
 (0)