1- import { encodeFunctionData , erc20Abi , formatEther , getAbiItem , Hex } from 'viem' ;
1+ import { encodeFunctionData , erc20Abi , formatEther , formatUnits , getAbiItem , Hex } from 'viem' ;
22import { SynthetixSdk } from '..' ;
33import {
44 CollateralData ,
@@ -47,6 +47,7 @@ import { MetadataResponse, PythPriceId } from '../interface/Markets';
4747import { erc20StateOverrideBalanceAndAllowance } from '../utils/override' ;
4848import { SYNTHETIX_ZAP_ABI } from '../contracts/abis/zap' ;
4949import { SYNTHETIX_ZAP } from '../contracts/addreses/zap' ;
50+ import { DEFAULT_DECIMALS } from '../constants' ;
5051
5152/**
5253 * Class for interacting with Synthetix Perps V3 contracts
@@ -1156,6 +1157,13 @@ export class Perps extends Market<MarketData> implements PerpsRepository {
11561157 return convertWeiToEther ( debt ) ;
11571158 }
11581159
1160+ /**
1161+ * Fetch Position and related margin details from contracts
1162+ * @param accountId The id of the account to get the debt for
1163+ * @param marketIdOrName Market
1164+ * @param override override params for the call
1165+ * @returns Formatted values in decimal numbers for position and margin data
1166+ */
11591167 protected async _getPositionData ( accountId : bigint , marketIdOrName : MarketIdOrName , override ?: OverrideParamsRead ) {
11601168 if ( ! accountId ) throw new Error ( 'Account ID is required' ) ;
11611169 const marketProxy = await this . sdk . contracts . getPerpsMarketProxyInstance ( ) ;
@@ -1190,39 +1198,21 @@ export class Perps extends Market<MarketData> implements PerpsRepository {
11901198 override ,
11911199 ) ;
11921200
1201+ const availableMargin = multicallResponse . at ( 0 ) as bigint ;
1202+ const requiredMaintenanceMargin = ( multicallResponse . at ( 1 ) as bigint [ ] ) . at ( 1 ) as bigint ;
1203+ const requiredInitialMargin = ( multicallResponse . at ( 1 ) as bigint [ ] ) . at ( 0 ) as bigint ;
1204+ const positionSize = multicallResponse . at ( 2 ) as bigint ;
1205+ const indexPrice = multicallResponse . at ( 3 ) as bigint ;
1206+
11931207 return {
1194- availableMargin : multicallResponse . at ( 0 ) as bigint ,
1195- requiredMaintenanceMargin : ( multicallResponse . at ( 1 ) as bigint [ ] ) . at ( 1 ) as bigint ,
1196- requiredInitialMargin : ( multicallResponse . at ( 1 ) as bigint [ ] ) . at ( 0 ) as bigint ,
1197- positionSize : multicallResponse . at ( 2 ) as bigint ,
1198- indexPrice : multicallResponse . at ( 3 ) as bigint ,
1208+ availableMargin : Number ( formatUnits ( availableMargin , DEFAULT_DECIMALS ) ) ,
1209+ requiredMaintenanceMargin : Number ( formatUnits ( requiredMaintenanceMargin , DEFAULT_DECIMALS ) ) ,
1210+ requiredInitialMargin : Number ( formatUnits ( requiredInitialMargin , DEFAULT_DECIMALS ) ) ,
1211+ positionSize : Number ( formatUnits ( positionSize , DEFAULT_DECIMALS ) ) ,
1212+ indexPrice : Number ( formatUnits ( indexPrice , DEFAULT_DECIMALS ) ) ,
11991213 } ;
12001214 }
12011215
1202- public async calculateApproxLiquidationPrice ( {
1203- collateralAmount,
1204- marketIdOrName,
1205- sizeAmount,
1206- accountId,
1207- collateralIdOrName,
1208- } : {
1209- collateralAmount : number ;
1210- marketIdOrName : MarketIdOrName ;
1211- sizeAmount : number ;
1212- accountId : bigint ;
1213- collateralIdOrName : MarketIdOrName ;
1214- } ) {
1215- const { requiredMaintenanceMargin, indexPrice } = await this . _getPositionData ( accountId , marketIdOrName ) ;
1216-
1217- const amount = await this . formatSize ( collateralAmount , marketIdOrName ) ;
1218- const size = await this . sdk . spot . formatSize ( sizeAmount , collateralIdOrName ) ;
1219-
1220- const healthFactor = ( amount * 100n ) / size ;
1221- const liquidationPrice = requiredMaintenanceMargin - amount / size + indexPrice ;
1222-
1223- return { healthFactor, liquidationPrice } ;
1224- }
1225-
12261216 /**
12271217 * Calculate the approximate liquidation price for an account with single position
12281218 * Provide either a ``marketId`` or a ``marketName``
@@ -1235,22 +1225,29 @@ export class Perps extends Market<MarketData> implements PerpsRepository {
12351225 marketIdOrName : MarketIdOrName ,
12361226 accountId = this . defaultAccountId ,
12371227 override ?: OverrideParamsRead ,
1238- ) : Promise < { healthFactor : bigint ; liquidationPrice : bigint } > {
1228+ ) : Promise < { healthFactor : number ; liquidationPrice : number } > {
12391229 if ( ! accountId ) throw new Error ( 'Account ID is required' ) ;
12401230
1241- const { availableMargin , requiredMaintenanceMargin , positionSize , indexPrice } = await this . _getPositionData (
1231+ const { positionSize , availableMargin , requiredMaintenanceMargin , indexPrice } = await this . _getPositionData (
12421232 accountId ,
12431233 marketIdOrName ,
12441234 override ,
12451235 ) ;
12461236
1247- const healthFactor = ( availableMargin * 100n ) / ( requiredMaintenanceMargin + 1n ) ;
1237+ const healthFactor = ( availableMargin * 100 ) / ( requiredMaintenanceMargin + 1 ) ;
1238+
1239+ // For invalid position, return current market price
1240+ if ( positionSize == 0 ) return { healthFactor, liquidationPrice : indexPrice } ;
12481241
1249- if ( positionSize == 0n ) {
1250- return { healthFactor, liquidationPrice : 0n } ;
1242+ const lossPerToken = ( requiredMaintenanceMargin - availableMargin ) / positionSize ;
1243+
1244+ let liquidationPrice ;
1245+ if ( positionSize > 0 ) {
1246+ liquidationPrice = indexPrice - lossPerToken ;
1247+ } else {
1248+ liquidationPrice = indexPrice + lossPerToken ;
12511249 }
12521250
1253- const liquidationPrice = ( requiredMaintenanceMargin - availableMargin ) / positionSize + indexPrice ;
12541251 return { healthFactor, liquidationPrice } ;
12551252 }
12561253
@@ -1259,12 +1256,14 @@ export class Perps extends Market<MarketData> implements PerpsRepository {
12591256 * @param {bigint } accountId The id of the account to calculate health factor.
12601257 * If not provided, the default account is used.
12611258 * @returns healthFactor percentage;
1259+ * @returns availableMargin Formatted available margin in USD;
1260+ * @returns requiredMaintenanceMargin Formatted required maintenance margin in USD
12621261 * healthFactor = (available margin * 100) / maintenance margin
12631262 */
12641263 public async getHealthFactor (
12651264 accountId = this . defaultAccountId ,
12661265 override ?: OverrideParamsRead ,
1267- ) : Promise < { healthFactor : bigint ; availableMargin : bigint ; requiredMaintenanceMargin : bigint } > {
1266+ ) : Promise < { healthFactor : number ; availableMargin : number ; requiredMaintenanceMargin : number } > {
12681267 if ( ! accountId ) throw new Error ( 'Account ID is required' ) ;
12691268 const marketProxy = await this . sdk . contracts . getPerpsMarketProxyInstance ( ) ;
12701269
@@ -1290,14 +1289,14 @@ export class Perps extends Market<MarketData> implements PerpsRepository {
12901289 ) ;
12911290
12921291 // 0. Available Margin
1293- const availableMargin = multicallResponse . at ( 0 ) as bigint ;
1292+ const availableMargin = Number ( formatUnits ( multicallResponse . at ( 0 ) as bigint , DEFAULT_DECIMALS ) ) ;
12941293
12951294 // 1. Required margin
12961295 // returns (uint256 requiredInitialMargin,uint256 requiredMaintenanceMargin,uint256 maxLiquidationReward)
12971296 const requiredMarginsResponse = multicallResponse . at ( 1 ) as bigint [ ] ;
1298- const requiredMaintenanceMargin = requiredMarginsResponse . at ( 1 ) as bigint ;
1297+ const requiredMaintenanceMargin = Number ( formatUnits ( requiredMarginsResponse . at ( 1 ) as bigint , DEFAULT_DECIMALS ) ) ;
12991298
1300- const healthFactor = ( availableMargin * 100n ) / ( requiredMaintenanceMargin + 1n ) ;
1299+ const healthFactor = ( availableMargin * 100 ) / ( requiredMaintenanceMargin + 1 ) ;
13011300 return { healthFactor, availableMargin, requiredMaintenanceMargin } ;
13021301 }
13031302
0 commit comments