diff --git a/package-lock.json b/package-lock.json index 77416e3..9bc7d31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@parifi/sdk", - "version": "0.1.13", + "version": "0.1.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@parifi/sdk", - "version": "0.1.13", + "version": "0.1.14", "license": "ISC", "dependencies": { "@gelatonetwork/relay-sdk": "^5.5.5", @@ -16,7 +16,9 @@ "dotenv": "^16.4.1", "ethers": "^6.10.0", "graphql": "^16.8.1", - "graphql-request": "^6.1.0" + "graphql-request": "^6.1.0", + "permissionless": "^0.1.16", + "viem": "^2.9.17" }, "devDependencies": { "@types/jest": "^29.5.11", @@ -1319,6 +1321,58 @@ "viem": "^1.14.0" } }, + "node_modules/@parifi/references/node_modules/abitype": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-0.9.8.tgz", + "integrity": "sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wagmi-dev" + } + ], + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3 >=3.19.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/@parifi/references/node_modules/viem": { + "version": "1.21.4", + "resolved": "https://registry.npmjs.org/viem/-/viem-1.21.4.tgz", + "integrity": "sha512-BNVYdSaUjeS2zKQgPs+49e5JKocfo60Ib2yiXOWBT6LuVxY1I/6fFX3waEtpXvL1Xn4qu+BVitVtMh9lyThyhQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.0", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@scure/bip32": "1.3.2", + "@scure/bip39": "1.2.1", + "abitype": "0.9.8", + "isows": "1.0.3", + "ws": "8.13.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1533,18 +1587,15 @@ "dev": true }, "node_modules/abitype": { - "version": "0.9.8", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-0.9.8.tgz", - "integrity": "sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wagmi-dev" - } - ], + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.0.tgz", + "integrity": "sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ==", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, "peerDependencies": { "typescript": ">=5.0.4", - "zod": "^3 >=3.19.1" + "zod": "^3 >=3.22.0" }, "peerDependenciesMeta": { "typescript": { @@ -4304,6 +4355,14 @@ "node": ">=8" } }, + "node_modules/permissionless": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/permissionless/-/permissionless-0.1.16.tgz", + "integrity": "sha512-UGC3yJiGYcPHJ+LohSFJSIxQGIQ2DMREYXGwVtb0DdvTVuO+uqqEymD6LZnKdtLF2KGhBPODv37LqvRyh+ma3g==", + "peerDependencies": { + "viem": "^2.0.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -5270,9 +5329,9 @@ } }, "node_modules/viem": { - "version": "1.21.4", - "resolved": "https://registry.npmjs.org/viem/-/viem-1.21.4.tgz", - "integrity": "sha512-BNVYdSaUjeS2zKQgPs+49e5JKocfo60Ib2yiXOWBT6LuVxY1I/6fFX3waEtpXvL1Xn4qu+BVitVtMh9lyThyhQ==", + "version": "2.9.17", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.9.17.tgz", + "integrity": "sha512-xMQ4JhgR1fPXQYagEeSsq9lmKXXooHP2gcnowb0eJRq3NTheyzpVBtMuH8DZnnWT4aeFepZktqSXlFul+Ou5Xg==", "funding": [ { "type": "github", @@ -5285,7 +5344,7 @@ "@noble/hashes": "1.3.2", "@scure/bip32": "1.3.2", "@scure/bip39": "1.2.1", - "abitype": "0.9.8", + "abitype": "1.0.0", "isows": "1.0.3", "ws": "8.13.0" }, diff --git a/package.json b/package.json index 00278aa..92494e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@parifi/sdk", - "version": "0.1.13", + "version": "0.1.14", "description": "Parifi SDK with common utility functions", "files": [ "dist", @@ -52,6 +52,8 @@ "dotenv": "^16.4.1", "ethers": "^6.10.0", "graphql": "^16.8.1", - "graphql-request": "^6.1.0" + "graphql-request": "^6.1.0", + "permissionless": "^0.1.16", + "viem": "^2.9.17" } } diff --git a/src/common/constants.ts b/src/common/constants.ts index c244e92..04a442c 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -25,3 +25,6 @@ export const PYTH_ETH_USD_PRICE_ID_STABLE = '0xff61491a931112ddf1bd8147cd1b64137 export const PYTH_USDC_USD_PRICE_ID_BETA = '0x41f3625971ca2ed2263e78573fe5ce23e13d2558ed3f2e47ab0f84fb9e7ae722'; export const PYTH_USDC_USD_PRICE_ID_STABLE = '0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a'; + +// Constants for Pimlico relayer +export const FACTORY_ADDRESS_SIMPLE_ACCOUNT = '0x91E60e0613810449d098b0b5Ec8b51A0FE8c8985' \ No newline at end of file diff --git a/src/core/order-manager/index.ts b/src/core/order-manager/index.ts index 6de74f3..ecaaa4f 100644 --- a/src/core/order-manager/index.ts +++ b/src/core/order-manager/index.ts @@ -17,7 +17,7 @@ import { AxiosInstance } from 'axios'; import { getPythPriceIdsForOrderIds, getPythPriceIdsForPositionIds } from '../../subgraph'; import { getVaaPriceUpdateData } from '../../pyth/pyth'; import { getPriceIdsForCollaterals } from '../../common'; -import { executeTxUsingGelato } from '../../gelato/gelato-function'; +import { executeTxUsingGelato } from '../../relayers/gelato/gelato-function'; // Returns an Order Manager contract instance without signer export const getOrderManagerInstance = (chain: Chain): Contract => { diff --git a/src/core/parifi-utils/index.ts b/src/core/parifi-utils/index.ts index 7288de5..59edd93 100644 --- a/src/core/parifi-utils/index.ts +++ b/src/core/parifi-utils/index.ts @@ -7,8 +7,8 @@ import { // normalizePythPriceForParifi } from '../../pyth/pyth'; import { AxiosInstance } from 'axios'; -import { executeTxUsingGelato } from '../../gelato/gelato-function'; -import { getAllPendingOrders, getPythPriceIdsForPositionIds } from '../../subgraph'; +import { executeTxUsingGelato } from '../../relayers/gelato/gelato-function'; +import { getAllPendingOrders, getPythPriceIdsForOrderIds, getPythPriceIdsForPositionIds } from '../../subgraph'; import { BatchExecute } from '../../interfaces/subgraphTypes'; import { DEFAULT_BATCH_COUNT, @@ -16,6 +16,7 @@ import { GAS_LIMIT_SETTLEMENT, getPriceIdsForCollaterals, } from '../../common'; +import { executeTxUsingPimlico } from '../../relayers/pimlico/utils'; // import { checkIfOrderCanBeSettled } from '../order-manager'; // Returns an Order Manager contract instance without signer @@ -248,3 +249,77 @@ export const batchSettleOrdersUsingWallet = async ( } return { txHash: '0x' }; }; + +// Returns encoded tx data to batch settle multiple orders +export const getBatchSettleTxData = async ( + chainId: Chain, + subgraphEndpoint: string, + pythClient: AxiosInstance, + orderIds: string[], +): Promise<{ txData: string }> => { + if (orderIds.length == 0) { + console.log('Orders not available for settlement'); + return { txData: '0x' }; + } + + const priceIds = await getPythPriceIdsForOrderIds(subgraphEndpoint, orderIds); + + // Get Price IDs of collateral tokens + const priceIdsForCollaterals = getPriceIdsForCollaterals(true); + + // Get Price update data and latest prices from Pyth + const priceUpdateData = await getVaaPriceUpdateData(priceIds.concat(priceIdsForCollaterals), pythClient); + + // Populate batched orders for settlement for orders that can be settled + const batchedOrders: BatchExecute[] = []; + + orderIds.forEach((orderId) => { + batchedOrders.push({ + id: orderId, + priceUpdateData: priceUpdateData, + }); + }); + + if (batchedOrders.length != 0) { + const parifiUtils = getParifiUtilsInstance(chainId); + const { data: txData } = await parifiUtils.batchSettleOrders.populateTransaction(batchedOrders); + return { txData }; + } + return { txData: '0x' }; +}; + +// Returns encoded tx data to batch liquidate multiple positions +export const getBatchLiquidateTxData = async ( + chainId: Chain, + subgraphEndpoint: string, + pythClient: AxiosInstance, + positionIds: string[], +): Promise<{ txData: string }> => { + if (positionIds.length == 0) return { txData: '0x' }; + + // Get unique price ids for all the positions + const priceIds = await getPythPriceIdsForPositionIds(subgraphEndpoint, positionIds); + + // Get Price IDs of collateral tokens + const priceIdsForCollaterals = getPriceIdsForCollaterals(true); + + // Get Price update data from Pyth + const priceUpdateData = await getVaaPriceUpdateData(priceIds.concat(priceIdsForCollaterals), pythClient); + + // Populate batched positions for positions that can be liquidated + const batchedPositions: BatchExecute[] = []; + positionIds.forEach((positionId) => { + batchedPositions.push({ + id: positionId, + priceUpdateData: priceUpdateData, + }); + }); + + // Encode transaction data + if (batchedPositions.length != 0) { + const parifiUtils = getParifiUtilsInstance(chainId); + const { data: txData } = await parifiUtils.batchLiquidatePositions.populateTransaction(batchedPositions); + return { txData }; + } + return { txData: '0x' }; +}; diff --git a/src/index.ts b/src/index.ts index bcdb77a..92d64c1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,13 +2,14 @@ import { Pyth } from './pyth'; import { Subgraph } from './subgraph'; import { PythConfig, RelayerConfig, RpcConfig, SubgraphConfig } from './interfaces/classConfigs'; import { Core } from './core'; -import { Gelato } from './gelato'; +import { Gelato } from './relayers/gelato'; import { relayerRepository } from './interfaces/repositories/relayer'; import { ParifiRelayer } from './relayers/parifi'; +import { Pimlico } from './relayers/pimlico'; export * from './common'; export * from './core'; -export * from './gelato/gelato-function'; +export * from './relayers/gelato/gelato-function'; export * from './interfaces'; export * from './pyth'; export * from './subgraph'; @@ -17,9 +18,10 @@ export class ParifiSdk { subgraph: Subgraph; pyth: Pyth; core: Core; - gelato: Gelato; relayer: { + gelato: Gelato; parifi: relayerRepository; + pimlico: Pimlico; }; constructor( @@ -31,13 +33,15 @@ export class ParifiSdk { this.subgraph = new Subgraph(rpcConfig, subgraphConfig, pythConfig); this.pyth = new Pyth(pythConfig); this.core = new Core(rpcConfig, subgraphConfig, relayerConfig, pythConfig); - this.gelato = new Gelato(relayerConfig['gelatoConfig'], rpcConfig); this.relayer = { + gelato: new Gelato(relayerConfig['gelatoConfig'], rpcConfig), parifi: new ParifiRelayer(relayerConfig['parifiRealyerConfig'], rpcConfig.chainId), + pimlico: new Pimlico(relayerConfig['pimlicoConfig'], rpcConfig, subgraphConfig), }; } async init() { await this.pyth.initPyth(); + await this.relayer.pimlico.initPimlico(); } } diff --git a/src/interfaces/classConfigs.ts b/src/interfaces/classConfigs.ts index 8989bde..bcfaf76 100644 --- a/src/interfaces/classConfigs.ts +++ b/src/interfaces/classConfigs.ts @@ -1,5 +1,6 @@ import { Chain } from '@parifi/references'; +// Interface to configure chain specific details of the sdk export interface RpcConfig { chainId: Chain; rpcEndpointUrl?: string; @@ -8,6 +9,7 @@ export interface RpcConfig { apiKey?: string; } +// Interface to configure subgraph details export interface SubgraphConfig { subgraphEndpoint?: string; username?: string; @@ -15,11 +17,14 @@ export interface SubgraphConfig { apiKey?: string; } +// Interface to configure relayers on the sdk export interface RelayerConfig { gelatoConfig?: RelayerI; parifiRealyerConfig?: RelayerI; + pimlicoConfig?: RelayerI; } +// Common relayer config to configure relayers export interface RelayerI { relayerEndpoint?: string; username?: string; @@ -28,6 +33,7 @@ export interface RelayerI { jwtToken?: string; } +// Pyth price feed config export interface PythConfig { pythEndpoint?: string; username?: string; diff --git a/src/gelato/gelato-function.ts b/src/relayers/gelato/gelato-function.ts similarity index 100% rename from src/gelato/gelato-function.ts rename to src/relayers/gelato/gelato-function.ts diff --git a/src/gelato/index.ts b/src/relayers/gelato/index.ts similarity index 92% rename from src/gelato/index.ts rename to src/relayers/gelato/index.ts index e51a3d6..573cfa8 100644 --- a/src/gelato/index.ts +++ b/src/relayers/gelato/index.ts @@ -1,5 +1,5 @@ import { TransactionStatusResponse } from '@gelatonetwork/relay-sdk'; -import { RelayerConfig, RpcConfig } from '../interfaces'; +import { RelayerConfig, RpcConfig } from '../../interfaces'; import { checkGelatoTaskStatus, executeTxUsingGelato } from './gelato-function'; export class Gelato { diff --git a/src/relayers/index.ts b/src/relayers/index.ts new file mode 100644 index 0000000..33e82ae --- /dev/null +++ b/src/relayers/index.ts @@ -0,0 +1,3 @@ +export * from './gelato'; +export * from './parifi'; +export * from './pimlico'; diff --git a/src/relayers/pimlico/index.ts b/src/relayers/pimlico/index.ts new file mode 100644 index 0000000..b7d7a2e --- /dev/null +++ b/src/relayers/pimlico/index.ts @@ -0,0 +1,84 @@ +import 'dotenv/config'; +import { RelayerConfig, RpcConfig, SubgraphConfig } from '../../interfaces'; +import { executeTxUsingPimlico, getPimlicoSmartAccountClient } from './utils'; +import { SmartAccount } from 'permissionless/accounts'; +import { Chain, Transport } from 'viem'; +import { EntryPoint } from 'permissionless/types/entrypoint'; +import { SmartAccountClient } from 'permissionless'; +import { getBatchLiquidateTxData, getBatchSettleTxData, getParifiUtilsInstance } from '../../core/parifi-utils'; +import { getPublicSubgraphEndpoint } from '../../subgraph'; +import { getPythClient } from '../../pyth/pyth'; + +import { contracts as parifiContracts } from '@parifi/references'; + +export class Pimlico { + /// Pimlico Class variables + public isInitialized: boolean; + private smartAccountClient: SmartAccountClient>; + + constructor( + private pimlicoConfig: RelayerConfig['pimlicoConfig'], + private rpcConfig: RpcConfig, + private subgraphConfig: SubgraphConfig, + ) { + this.isInitialized = false; + this.smartAccountClient = {} as SmartAccountClient>; + } + + //////////////////////////////////////////////////////////////// + ////////////////////// INITIALIZER /////////////////////// + //////////////////////////////////////////////////////////////// + async initPimlico() { + if (this.isInitialized) { + console.log('Pimlico relayer already initialized'); + return; + } + + if (this.pimlicoConfig?.apiKey === undefined || this.rpcConfig.rpcEndpointUrl === undefined) { + console.log('Invalid config for Pimlico'); + return; + } + + this.smartAccountClient = await getPimlicoSmartAccountClient(this.pimlicoConfig, this.rpcConfig); + + // Set the Pimlico Relayer as initialized + this.isInitialized = true; + } + + //////////////////////////////////////////////////////////////// + //////////////////// PUBLIC FUNCTIONS //////////////////// + //////////////////////////////////////////////////////////////// + public executeTxUsingPimlico = async (targetContractAddress: string, txData: string) => { + return await executeTxUsingPimlico(this.smartAccountClient, targetContractAddress, txData); + }; + + // Batch settle orders using Pimlico for OrderIds + public batchSettleOrdersUsingPimlico = async (orderIds: string[]): Promise<{ txHash: string }> => { + const chainId = this.rpcConfig.chainId; + const subgraphEndpoint = this.subgraphConfig.subgraphEndpoint ?? getPublicSubgraphEndpoint(chainId); + + const pythClient = await getPythClient(); + + // Get Settle orders transaction data for execution + const { txData } = await getBatchSettleTxData(chainId, subgraphEndpoint, pythClient, orderIds); + + const parifiUtilsAddress = parifiContracts[chainId].ParifiUtils.address; + + return await executeTxUsingPimlico(this.smartAccountClient, parifiUtilsAddress, txData); + }; + + // Batch settle orders using Pimlico for OrderIds + public batchLiquidatePositionsUsingPimlico = async (positionIds: string[]): Promise<{ txHash: string }> => { + const chainId = this.rpcConfig.chainId; + const subgraphEndpoint = this.subgraphConfig.subgraphEndpoint ?? getPublicSubgraphEndpoint(chainId); + + const pythClient = await getPythClient(); + + // Get Settle orders transaction data for execution + const { txData } = await getBatchLiquidateTxData(chainId, subgraphEndpoint, pythClient, positionIds); + + const parifiUtilsAddress = parifiContracts[chainId].ParifiUtils.address; + + return await executeTxUsingPimlico(this.smartAccountClient, parifiUtilsAddress, txData); + }; +} diff --git a/src/relayers/pimlico/utils.ts b/src/relayers/pimlico/utils.ts new file mode 100644 index 0000000..c890569 --- /dev/null +++ b/src/relayers/pimlico/utils.ts @@ -0,0 +1,96 @@ +import 'dotenv/config'; +import { arbitrum } from 'viem/chains'; +import { appendFileSync } from 'fs'; +import { ENTRYPOINT_ADDRESS_V07, SmartAccountClient, createSmartAccountClient } from 'permissionless'; +import { RelayerI, RpcConfig } from '../../interfaces'; +import { SmartAccount, privateKeyToSimpleSmartAccount } from 'permissionless/accounts'; +import { Chain, Hex, Transport, createPublicClient, http } from 'viem'; + +import { createPimlicoBundlerClient, createPimlicoPaymasterClient } from 'permissionless/clients/pimlico'; + +import { generatePrivateKey } from 'viem/accounts'; + +import { EntryPoint } from 'permissionless/types/entrypoint'; +import { FACTORY_ADDRESS_SIMPLE_ACCOUNT } from '../../common'; + +export const getPimlicoSmartAccountClient = async ( + pimlicoConfig: RelayerI, + rpcConfig: RpcConfig, +): Promise>> => { + const apiKey = pimlicoConfig.apiKey ?? ''; + const viemChain = getViemChainById(rpcConfig.chainId as number); + const chainId = rpcConfig.chainId as number; + + /// Create Paymaster Client + const paymasterUrl = `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apiKey}`; + const publicClient = createPublicClient({ + transport: http(rpcConfig.rpcEndpointUrl), + }); + + const paymasterClient = createPimlicoPaymasterClient({ + transport: http(paymasterUrl), + entryPoint: ENTRYPOINT_ADDRESS_V07, + }); + + /// Create Smart account for user address EOA + const privateKey = + (process.env.PRIVATE_KEY as Hex) ?? + (() => { + const pk = generatePrivateKey(); + appendFileSync('.env', `PRIVATE_KEY=${pk}`); + return pk; + })(); + + const account = await privateKeyToSimpleSmartAccount(publicClient, { + privateKey, + entryPoint: ENTRYPOINT_ADDRESS_V07, + factoryAddress: FACTORY_ADDRESS_SIMPLE_ACCOUNT, + }); + + /// Create Bundler client + const bundlerUrl = `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apiKey}`; + const bundlerClient = createPimlicoBundlerClient({ + transport: http(bundlerUrl), + entryPoint: ENTRYPOINT_ADDRESS_V07, + }); + + /// Create Smart account client + const smartAccountClient = createSmartAccountClient({ + account, + entryPoint: ENTRYPOINT_ADDRESS_V07, + chain: viemChain, + bundlerTransport: http(bundlerUrl), + middleware: { + gasPrice: async () => { + return (await bundlerClient.getUserOperationGasPrice()).fast; + }, + sponsorUserOperation: paymasterClient.sponsorUserOperation, + }, + }) as SmartAccountClient>; + + return smartAccountClient; +}; + +export const executeTxUsingPimlico = async ( + smartAccountClient: SmartAccountClient>, + targetContractAddress: string, + txData: string, +): Promise<{ txHash: string }> => { + const txHash = await smartAccountClient.sendTransaction({ + to: targetContractAddress as Hex, + value: 0n, + data: txData as Hex, + }); + return { txHash }; +}; + +/** + * Gets the chain object for the given chain id. + * @param chainId - Chain id of the target EVM chain. + * @returns Viem's chain object. + */ +export const getViemChainById = (chainId: number) => { + if (chainId === 42161) { + return arbitrum; + } +}; diff --git a/test/SDKClass-test/sdk.test.ts b/test/SDKClass-test/sdk.test.ts deleted file mode 100644 index 5e488a6..0000000 --- a/test/SDKClass-test/sdk.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import 'dotenv/config'; -import { Chain } from '@parifi/references'; -import { ParifiSdk } from '../../src'; -import { PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../../src/interfaces/classConfigs'; - -const chain = Chain.ARBITRUM_SEPOLIA; -const rpcConfig: RpcConfig = { - chainId: chain, -}; - -const pythConfig: PythConfig = { - pythEndpoint: process.env.PYTH_SERVICE_ENDPOINT, - username: process.env.PYTH_SERVICE_USERNAME, - password: process.env.PYTH_SERVICE_PASSWORD, - isStable: true, -}; - -const subgraphConfig: SubgraphConfig = {}; - -const gelatoConfig: RelayerI = { - apiKey: process.env.GELATO_KEY || '', -}; - -const relayerConfig: RelayerConfig = { - gelatoConfig: gelatoConfig, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, subgraphConfig, relayerConfig, pythConfig); - -describe('sdkTest', () => { - it('should return correct position details', async () => { - await parifiSdk.init(); - const positionId = '0x5c46fe7154af223da5e2e6d284e367d4ef38bdfd5c6fd4ce56cc47d0d3cbd957'; - - const position = await parifiSdk.subgraph.getPositionById(positionId); - expect(position.id).toBe(positionId); - }); -}); - -describe('Pyth tests', () => { - it('should return price update data from public endpoint', async () => { - await parifiSdk.init(); - const ethPriceIdStable = '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace'; - - const priceUpdateData = await parifiSdk.pyth.getVaaPriceUpdateData([ethPriceIdStable]); - console.log(priceUpdateData); - expect(priceUpdateData).not.toBeNull(); - }); -}); diff --git a/test/common/constants.ts b/test/common/constants.ts new file mode 100644 index 0000000..27dc120 --- /dev/null +++ b/test/common/constants.ts @@ -0,0 +1,27 @@ + +// Test values for ARBITRUM MAINNET +export const TEST_ORDER_ID1 = '0x5f0aafacb19b261b533339322f45542f33e5e20ff71b0374320b69713f59695d'; +export const TEST_ORDER_ID2 = '0x00b6618941043e002c541b3440da7dcf143137d06cf44648448e0164d3e1f51d'; +export const TEST_ORDER_ID3 = '0x0603ee66b7b5e58889da9241ea421b2ddb65b68fc606f0bfa28cda9920b397af'; +export const TEST_ORDER_ID4 = ''; + +export const TEST_POSITION_ID1 = '0x08df72fc01f549908150f60f64bd5eb4228fa755d420bd28d3ec2f2957a543f2'; +export const TEST_POSITION_ID2 = ''; +export const TEST_POSITION_ID3 = ''; +export const TEST_POSITION_ID4 = ''; + +export const TEST_USER_ID1 = '0xb0881c72cc2aea56cfcaa2e1197b6d87b8f6b11b'; +export const TEST_USER_ID2 = '0x58d24685a6982CbEE9d43f3e915B4A6EA12bB3c6'; +export const TEST_USER_ID3 = '0xe4fDB1Fa65b29533D6d3D9Aa74e07E6e87405B32'; +export const TEST_USER_ID4 = '0xd60202464e7d923dea9c2b2f5435597e51de2683'; + +export const TEST_MARKET_ID1 = '0x8be0f114459933877db428bcb6955e666e09cb7de93b6c08747d3ef329b6875c'; +export const TEST_MARKET_ID2 = ''; + +export const TEST_VAULT_ID1 = '0x13a78809528b02ad5e7c42f39232d332761dfb1d'; +export const TEST_VAULT_ID2 = ''; + +export const TEST_SETTLE_ORDER_ID = '0x60d484b457d3ab8c69eb39fb3bb46dedce558189b1deb124f99cc667669d5df4' +export const TEST_LIQUIDATE_POS_ID = '0x00841110ab1304773ceb680ae39dcd0a50d3326a50de33aab6792d17a4483b04' + +export const TEST_PRICE_ID_1 = '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace' \ No newline at end of file diff --git a/test/core/orderManager.test.ts b/test/core/orderManager.test.ts index 57d9185..988fbe2 100644 --- a/test/core/orderManager.test.ts +++ b/test/core/orderManager.test.ts @@ -1,39 +1,10 @@ -import 'dotenv/config'; -import { Chain } from '@parifi/references'; -import { PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../../src/interfaces/classConfigs'; -import { ParifiSdk } from '../../src'; import { ethers } from 'ethers'; +import { getParifiSdkInstanceForTesting } from '..'; +import { TEST_SETTLE_ORDER_ID } from '../common/constants'; -const chain = Chain.ARBITRUM_MAINNET; -const rpcConfig: RpcConfig = { - chainId: chain, -}; - -const subgraphConfig: SubgraphConfig = { - subgraphEndpoint: process.env.SUBGRAPH_ENDPOINT, -}; - -const pythConfig: PythConfig = { - pythEndpoint: process.env.PYTH_SERVICE_ENDPOINT, - username: process.env.PYTH_SERVICE_USERNAME, - password: process.env.PYTH_SERVICE_PASSWORD, - isStable: true, -}; - -const gelatoConfig: RelayerI = { - apiKey: process.env.GELATO_KEY || '', -}; - -const relayerConfig: RelayerConfig = { - gelatoConfig: gelatoConfig, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, subgraphConfig, relayerConfig, pythConfig); -// -// gelato say too many requests describe('Order Manager tests', () => { it('should liquidate a single position', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); let positionId: string; const positionsToLiquidate = await parifiSdk.subgraph.getPositionsToLiquidate(); @@ -46,15 +17,15 @@ describe('Order Manager tests', () => { const { gelatoTaskId } = await parifiSdk.core.liquidatePositionUsingGelato(positionId); console.log('taskId', gelatoTaskId); - const taskStatus = await parifiSdk.gelato.checkGelatoTaskStatus(gelatoTaskId); + const taskStatus = await parifiSdk.relayer.gelato.checkGelatoTaskStatus(gelatoTaskId); console.log('taskStatus', taskStatus); } }); it('should settle single order using wallet', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); - const orderIds = ['0x5f0aafacb19b261b533339322f45542f33e5e20ff71b0374320b69713f59695d']; + const orderIds = [TEST_SETTLE_ORDER_ID]; const priceIds = await parifiSdk.subgraph.getPythPriceIdsForOrderIds(orderIds); diff --git a/test/core/parifi-utils.test.ts b/test/core/parifi-utils.test.ts index d64ab1e..fc41f53 100644 --- a/test/core/parifi-utils.test.ts +++ b/test/core/parifi-utils.test.ts @@ -1,54 +1,26 @@ -import 'dotenv/config'; -import { Chain } from '@parifi/references'; -import { PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../../src/interfaces/classConfigs'; -import { ParifiSdk } from '../../src'; import { ethers } from 'ethers'; - -const chain = Chain.ARBITRUM_SEPOLIA; -const rpcConfig: RpcConfig = { - chainId: chain, -}; - -const pythConfig: PythConfig = { - pythEndpoint: process.env.PYTH_SERVICE_ENDPOINT, - username: process.env.PYTH_SERVICE_USERNAME, - password: process.env.PYTH_SERVICE_PASSWORD, - isStable: true, -}; - -const gelatoConfig: RelayerI = { - apiKey: process.env.GELATO_KEY || '', -}; - -const relayerConfig: RelayerConfig = { - gelatoConfig: gelatoConfig, -}; - -const subgraphConfig: SubgraphConfig = { - subgraphEndpoint: process.env.SUBGRAPH_ENDPOINT, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, subgraphConfig, relayerConfig, pythConfig); +import { getParifiSdkInstanceForTesting } from '..'; +import { TEST_LIQUIDATE_POS_ID } from '../common/constants'; describe('Parifi Utils tests', () => { it('should settle orders in batch using Parifi Utils', async () => { // To test the batch settle functionality, create some orders manually using the interface - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); const orderCount = await parifiSdk.core.batchSettlePendingOrdersUsingGelato(); console.log('Orders processed: ', orderCount); }); it('should liquidate positions in batch using Parifi Utils', async () => { // To test the batch liquidate functionality, add correct position ids below - await parifiSdk.init(); - const positionIds = ['0x00841110ab1304773ceb680ae39dcd0a50d3326a50de33aab6792d17a4483b04']; + const parifiSdk = await getParifiSdkInstanceForTesting(); + const positionIds = [TEST_LIQUIDATE_POS_ID]; const positionsCount = await parifiSdk.core.batchLiquidatePositionsUsingGelato(positionIds); console.log('Positions processed: ', positionsCount); }); it('should settle orders in batch using an external wallet', async () => { // To test the batch settle functionality, create some orders manually using the interface - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); // Get orders that can be settled in the next 30 seconds const expiryTimestamp = Math.floor(Date.now() / 1000); diff --git a/test/core/relayer.test.ts b/test/core/relayer.test.ts index d4a94a9..a987200 100644 --- a/test/core/relayer.test.ts +++ b/test/core/relayer.test.ts @@ -1,35 +1,8 @@ -import { Chain } from '@parifi/references'; -import { ParifiSdk, PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../../src'; - -const chain = Chain.ARBITRUM_SEPOLIA; -const rpcConfig: RpcConfig = { - chainId: chain, -}; - -const pythConfig: PythConfig = { - pythEndpoint: process.env.PYTH_SERVICE_ENDPOINT, - username: process.env.PYTH_SERVICE_USERNAME, - password: process.env.PYTH_SERVICE_PASSWORD, - isStable: true, -}; - -const parifiConfig: RelayerI = { - jwtToken: process.env.PARIFI_RELAYER_JWT_TOKEN || '', - // relayerEndpoint: 'http://localhost:3001', -}; - -const relayerConfig: RelayerConfig = { - parifiRealyerConfig: parifiConfig, -}; - -const subgraphConfig: SubgraphConfig = { - subgraphEndpoint: process.env.SUBGRAPH_ENDPOINT, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, subgraphConfig, relayerConfig, pythConfig); +import { getParifiSdkInstanceForTesting } from '..'; describe('ParifiSdk parifi relayer', () => { it.skip('should return txId', async () => { + const parifiSdk = await getParifiSdkInstanceForTesting(); const txId = await parifiSdk.relayer.parifi.executeTx({ to: '0x15758472aF37950028ad27e4a7F99e65A4A997Cc', data: '0x095ea7b30000000000000000000000003232f21a6e08312654270c78a773f00dd61d60f500000000000000000000000000000000000000000000000000000000000003e8', diff --git a/test/core/stats.test.ts b/test/core/stats.test.ts index 30aa78a..c7eaf14 100644 --- a/test/core/stats.test.ts +++ b/test/core/stats.test.ts @@ -1,29 +1,13 @@ -import 'dotenv/config'; -import { Chain } from '@parifi/references'; -import { ParifiSdk } from '../../src'; import Decimal from 'decimal.js'; -import { RelayerConfig, RelayerI, RpcConfig } from '../../src/interfaces/classConfigs'; import { getMarketBorrowingRatePerHour, getMarketOpenInterestInUsd } from '../../src/core/pages/statsPage'; - -const rpcConfig: RpcConfig = { - chainId: Chain.ARBITRUM_SEPOLIA, -}; - -const gelatoConfig: RelayerI = { - apiKey: process.env.GELATO_KEY || '', -}; - -const relayerConfig: RelayerConfig = { - gelatoConfig: gelatoConfig, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, {}, relayerConfig, {}); +import { getParifiSdkInstanceForTesting } from '..'; +import { TEST_MARKET_ID1 } from '../common/constants'; describe('Stats tests', () => { it('should return correct borrowing fees for market', async () => { - await parifiSdk.init(); - const marketId = '0x122d17f9d86438d3f9d12c1366a56e45c03ae191f705a5d850617739f76605d5'; - const market = await parifiSdk.subgraph.getMarketById(marketId); + const parifiSdk = await getParifiSdkInstanceForTesting(); + + const market = await parifiSdk.subgraph.getMarketById(TEST_MARKET_ID1); const totalLongs = new Decimal(market.totalLongs ?? '0'); const totalShorts = new Decimal(market.totalShorts ?? '0'); @@ -39,10 +23,9 @@ describe('Stats tests', () => { }); it('should return correct Open Interest market', async () => { - await parifiSdk.init(); - const marketId = '0x122d17f9d86438d3f9d12c1366a56e45c03ae191f705a5d850617739f76605d5'; + const parifiSdk = await getParifiSdkInstanceForTesting(); - const market = await parifiSdk.subgraph.getMarketById(marketId); + const market = await parifiSdk.subgraph.getMarketById(TEST_MARKET_ID1); const normalizedMarketPrice = new Decimal(market.pyth?.price ?? '1800000000'); // Price fetched from the subgraph for testing const totalOIInUsd = new Decimal(market.totalOI ?? '0'); diff --git a/test/index.ts b/test/index.ts new file mode 100644 index 0000000..5aa0810 --- /dev/null +++ b/test/index.ts @@ -0,0 +1,38 @@ +import { Chain } from '@parifi/references'; +import { ParifiSdk, PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../src'; + +export const getParifiSdkInstanceForTesting = async (): Promise => { + const chain = Chain.ARBITRUM_MAINNET; + const rpcConfig: RpcConfig = { + chainId: chain, + rpcEndpointUrl: process.env.RPC_ARBITRUM + }; + + const subgraphConfig: SubgraphConfig = { + subgraphEndpoint: process.env.SUBGRAPH_ENDPOINT, + }; + + const pythConfig: PythConfig = { + pythEndpoint: process.env.PYTH_SERVICE_ENDPOINT, + username: process.env.PYTH_SERVICE_USERNAME, + password: process.env.PYTH_SERVICE_PASSWORD, + isStable: true, + }; + + const gelatoConfig: RelayerI = { + apiKey: process.env.GELATO_KEY || '', + }; + + const pimlicoConfig: RelayerI = { + apiKey: process.env.PIMLICO_API_KEY, + }; + + const relayerConfig: RelayerConfig = { + gelatoConfig: gelatoConfig, + pimlicoConfig: pimlicoConfig, + }; + + const parifiSdk = new ParifiSdk(rpcConfig, subgraphConfig, relayerConfig, pythConfig); + await parifiSdk.init(); + return parifiSdk; +}; diff --git a/test/pyth-tests/pyth.test.ts b/test/pyth-tests/pyth.test.ts index e0ea6a2..17f08a1 100644 --- a/test/pyth-tests/pyth.test.ts +++ b/test/pyth-tests/pyth.test.ts @@ -2,10 +2,12 @@ import 'dotenv/config'; import { Chain } from '@parifi/references'; // import { getPythClient, getVaaPriceUpdateData } from '../../src/pyth'; import { ParifiSdk } from '../../src'; -import { PythConfig, RelayerConfig, RelayerI, RpcConfig } from '../../src/interfaces/classConfigs'; +import { PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../../src/interfaces/classConfigs'; +import { getParifiSdkInstanceForTesting } from '..'; +import { TEST_ORDER_ID1, TEST_ORDER_ID2, TEST_ORDER_ID3, TEST_PRICE_ID_1 } from '../common/constants'; const rpcConfig: RpcConfig = { - chainId: Chain.ARBITRUM_SEPOLIA, + chainId: Chain.ARBITRUM_MAINNET, }; const pythConfig: PythConfig = { @@ -23,39 +25,31 @@ const relayerConfig: RelayerConfig = { gelatoConfig: gelatoConfig, }; -const parifiSdk = new ParifiSdk(rpcConfig, {}, relayerConfig, pythConfig); - describe('Pyth tests', () => { it('should return price update data from public endpoint', async () => { - await parifiSdk.init(); - const ethPriceIdStable = '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace'; - // SDK is initialized without any fields for Pyth config, so public endpoints are used const sdkWithPublicPyth = new ParifiSdk(rpcConfig, {}, relayerConfig, pythConfig); await sdkWithPublicPyth.init(); - const priceUpdateData = await sdkWithPublicPyth.pyth.getVaaPriceUpdateData([ethPriceIdStable]); + const priceUpdateData = await sdkWithPublicPyth.pyth.getVaaPriceUpdateData([TEST_PRICE_ID_1]); console.log(priceUpdateData); expect(priceUpdateData).not.toBeNull(); }); it('should return price update data from dedicated endpoint with authentication', async () => { - await parifiSdk.init(); - const ethPriceIdStable = '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace'; + const parifiSdk = await getParifiSdkInstanceForTesting(); // Parifi SDK uses authentication using the above Pyth config - const priceUpdateData = await parifiSdk.pyth.getVaaPriceUpdateData([ethPriceIdStable]); + const priceUpdateData = await parifiSdk.pyth.getVaaPriceUpdateData([TEST_PRICE_ID_1]); console.log(priceUpdateData); expect(priceUpdateData).not.toBeNull(); }); it('should return price ids from subgraph', async () => { - await parifiSdk.init(); - const orderIds = [ - '0xb160ae39e7a45b21fb8f247fb11f551f996ed90d3eb9a6263e49b98827e1fc4b', - '0xbd8bdf1ed20ac4a074c0c6ccc49e1716b80cb734ed75b53668c15956c2bba494', - ]; + const parifiSdk = await getParifiSdkInstanceForTesting(); + + const orderIds = [TEST_ORDER_ID1, TEST_ORDER_ID2, TEST_ORDER_ID3]; const priceIds: string[] = await parifiSdk.subgraph.getPythPriceIdsForOrderIds(orderIds); console.log('priceIds from fn: ', priceIds); diff --git a/test/relayers/pimlico.test.ts b/test/relayers/pimlico.test.ts new file mode 100644 index 0000000..1905840 --- /dev/null +++ b/test/relayers/pimlico.test.ts @@ -0,0 +1,29 @@ +import { getParifiSdkInstanceForTesting } from '..'; +import { OrderStatus } from '../../src'; +import { TEST_SETTLE_ORDER_ID } from '../common/constants'; + +describe('Pimlico test cases', () => { + it.skip('should initialize Pimlico and send a sample tx', async () => { + const parifiSdk = await getParifiSdkInstanceForTesting(); + + const targetContractAddress = '0x58d24685a6982CbEE9d43f3e915B4A6EA12bB3c6'; + const txData = '0x123456789'; + const { txHash } = await parifiSdk.relayer.pimlico.executeTxUsingPimlico(targetContractAddress, txData); + + console.log(`User operation included: https://arbiscan.io/tx/${txHash}`); + }); + + it('should settle orders using Pimlico', async () => { + const parifiSdk = await getParifiSdkInstanceForTesting(); + + const orderDetails = await parifiSdk.subgraph.getOrderById(TEST_SETTLE_ORDER_ID); + if (orderDetails.status == OrderStatus.SETTLED) { + return; + } + const orderIds = [TEST_SETTLE_ORDER_ID]; + + const { txHash } = await parifiSdk.relayer.pimlico.batchSettleOrdersUsingPimlico(orderIds); + + console.log(`User operation included: https://arbiscan.io/tx/${txHash}`); + }); +}); diff --git a/test/subgraph-tests/accounts.test.ts b/test/subgraph-tests/accounts.test.ts index 3b286e7..600ca60 100644 --- a/test/subgraph-tests/accounts.test.ts +++ b/test/subgraph-tests/accounts.test.ts @@ -1,36 +1,9 @@ -import 'dotenv/config'; -import { Chain } from '@parifi/references'; -import { ParifiSdk } from '../../src'; -import { PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../../src/interfaces/classConfigs'; - -const rpcConfig: RpcConfig = { - chainId: Chain.ARBITRUM_SEPOLIA, -}; - -const subgraphConfig: SubgraphConfig = { - subgraphEndpoint: process.env.SUBGRAPH_ENDPOINT, -}; - -const pythConfig: PythConfig = { - pythEndpoint: process.env.PYTH_SERVICE_ENDPOINT, - username: process.env.PYTH_SERVICE_USERNAME, - password: process.env.PYTH_SERVICE_PASSWORD, - isStable: true, -}; - -const gelatoConfig: RelayerI = { - apiKey: process.env.GELATO_KEY, -}; - -const relayerConfig: RelayerConfig = { - gelatoConfig: gelatoConfig, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, subgraphConfig, relayerConfig, pythConfig); +import { getParifiSdkInstanceForTesting } from '..'; +import { TEST_USER_ID1, TEST_USER_ID2, TEST_USER_ID3 } from '../common/constants'; describe('Order fetching logic from subgraph', () => { it('should return PNL details for a user', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); // Use an address with a non-zero positions/deposits const userAddress = '0xe4fDB1Fa65b29533D6d3D9Aa74e07E6e87405B32'; @@ -46,16 +19,12 @@ describe('Order fetching logic from subgraph', () => { }); it('should return Portfolio total for user addresses', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); // Use addresses with a non-zero positions/deposits - const userAddresses = [ - '0xb0881c72cc2aea56cfcaa2e1197b6d87b8f6b11b', - '0x58d24685a6982CbEE9d43f3e915B4A6EA12bB3c6', - '0xe4fDB1Fa65b29533D6d3D9Aa74e07E6e87405B32', - ]; + const userAddresses = [TEST_USER_ID1, TEST_USER_ID2, TEST_USER_ID3]; const { portfolioData } = await parifiSdk.subgraph.getPortfolioDataForUsers(userAddresses); - console.log("portfolioData", portfolioData) + console.log('portfolioData', portfolioData); }); }); diff --git a/test/subgraph-tests/index.test.ts b/test/subgraph-tests/index.test.ts index c93a9d4..d0e516f 100644 --- a/test/subgraph-tests/index.test.ts +++ b/test/subgraph-tests/index.test.ts @@ -4,7 +4,7 @@ import { RpcConfig } from '../../src/interfaces/classConfigs'; import { gql } from 'graphql-request'; const rpcConfig: RpcConfig = { - chainId: Chain.ARBITRUM_SEPOLIA, + chainId: Chain.ARBITRUM_MAINNET, }; const parifiSdk = new ParifiSdk(rpcConfig, {}, {}, {}); diff --git a/test/subgraph-tests/market.test.ts b/test/subgraph-tests/market.test.ts index e114192..d79f53a 100644 --- a/test/subgraph-tests/market.test.ts +++ b/test/subgraph-tests/market.test.ts @@ -1,24 +1,11 @@ -import { Chain } from '@parifi/references'; -import { ParifiSdk } from '../../src'; -import { RelayerConfig, RelayerI, RpcConfig } from '../../src/interfaces/classConfigs'; - -const rpcConfig: RpcConfig = { - chainId: Chain.ARBITRUM_SEPOLIA, -}; -const gelatoConfig: RelayerI = { - apiKey: process.env.GELATO_KEY || '', -}; - -const relayerConfig: RelayerConfig = { - gelatoConfig: gelatoConfig, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, {}, relayerConfig, {}); +import { getParifiSdkInstanceForTesting } from '..'; +import { TEST_MARKET_ID1 } from '../common/constants'; describe('Market fetching logic from subgraph', () => { it('should return correct market details', async () => { - await parifiSdk.init(); - const marketId = '0x122d17f9d86438d3f9d12c1366a56e45c03ae191f705a5d850617739f76605d5'; + const parifiSdk = await getParifiSdkInstanceForTesting(); + + const marketId = TEST_MARKET_ID1; const market = await parifiSdk.subgraph.getMarketById(marketId); diff --git a/test/subgraph-tests/orders.test.ts b/test/subgraph-tests/orders.test.ts index 7e40566..1328130 100644 --- a/test/subgraph-tests/orders.test.ts +++ b/test/subgraph-tests/orders.test.ts @@ -1,45 +1,18 @@ -import 'dotenv/config'; - -import { Chain } from '@parifi/references'; -import { OrderStatus, OrderType, ParifiSdk } from '../../src'; -import { PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../../src/interfaces/classConfigs'; -const rpcConfig: RpcConfig = { - chainId: Chain.ARBITRUM_SEPOLIA, -}; - -const subgraphConfig: SubgraphConfig = { - subgraphEndpoint: process.env.SUBGRAPH_ENDPOINT, -}; - -const pythConfig: PythConfig = { - pythEndpoint: process.env.PYTH_SERVICE_ENDPOINT, - username: process.env.PYTH_SERVICE_USERNAME, - password: process.env.PYTH_SERVICE_PASSWORD, - isStable: true, -}; - -const gelatoConfig: RelayerI = { - apiKey: process.env.GELATO_KEY, -}; - -const relayerConfig: RelayerConfig = { - gelatoConfig: gelatoConfig, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, subgraphConfig, relayerConfig, pythConfig); +import { getParifiSdkInstanceForTesting } from '..'; +import { OrderStatus } from '../../src'; +import { TEST_ORDER_ID1, TEST_SETTLE_ORDER_ID } from '../common/constants'; describe('Order fetching logic from subgraph', () => { it('should return correct order details', async () => { - await parifiSdk.init(); - const orderId = '0x0603ee66b7b5e58889da9241ea421b2ddb65b68fc606f0bfa28cda9920b397af'; + const parifiSdk = await getParifiSdkInstanceForTesting(); - const order = await parifiSdk.subgraph.getOrderById(orderId); - expect(order.id).toBe(orderId); + const order = await parifiSdk.subgraph.getOrderById(TEST_ORDER_ID1); + expect(order.id).toBe(TEST_ORDER_ID1); }); it('should settle order using Gelato', async () => { - await parifiSdk.init(); - const orderId = '0x0603ee66b7b5e58889da9241ea421b2ddb65b68fc606f0bfa28cda9920b397af'; + const parifiSdk = await getParifiSdkInstanceForTesting(); + const orderId = TEST_SETTLE_ORDER_ID; const order = await parifiSdk.subgraph.getOrderById(orderId); expect(order.id).toBe(orderId); @@ -51,7 +24,7 @@ describe('Order fetching logic from subgraph', () => { }); it('should return referral data for partner address', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); const partnerAddress = '0x30f06f86f107f9523f5b91a8e8aeb602b7b260bd'; const referralData = await parifiSdk.subgraph.getReferralDataForPartner(partnerAddress); diff --git a/test/subgraph-tests/position.test.ts b/test/subgraph-tests/position.test.ts index f7d9a58..fda469a 100644 --- a/test/subgraph-tests/position.test.ts +++ b/test/subgraph-tests/position.test.ts @@ -1,37 +1,17 @@ -import 'dotenv/config'; -import { Chain } from '@parifi/references'; -import { ParifiSdk } from '../../src'; -import { PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../../src/interfaces/classConfigs'; - -const rpcConfig: RpcConfig = { - chainId: Chain.ARBITRUM_SEPOLIA, -}; - -const subgraphConfig: SubgraphConfig = { - subgraphEndpoint: process.env.SUBGRAPH_ENDPOINT, -}; - -const pythConfig: PythConfig = { - pythEndpoint: process.env.PYTH_SERVICE_ENDPOINT, - username: process.env.PYTH_SERVICE_USERNAME, - password: process.env.PYTH_SERVICE_PASSWORD, - isStable: true, -}; - -const gelatoConfig: RelayerI = { - apiKey: process.env.GELATO_KEY, -}; - -const relayerConfig: RelayerConfig = { - gelatoConfig: gelatoConfig, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, subgraphConfig, relayerConfig, pythConfig); +import { getParifiSdkInstanceForTesting } from '..'; +import { + TEST_POSITION_ID1, + TEST_POSITION_ID2, + TEST_POSITION_ID3, + TEST_USER_ID2, + TEST_USER_ID3, + TEST_USER_ID4, +} from '../common/constants'; describe('Order fetching logic from subgraph', () => { it('should return correct position details', async () => { - await parifiSdk.init(); - const positionId = '0x08df72fc01f549908150f60f64bd5eb4228fa755d420bd28d3ec2f2957a543f2'; + const parifiSdk = await getParifiSdkInstanceForTesting(); + const positionId = TEST_POSITION_ID1; const position = await parifiSdk.subgraph.getPositionById(positionId); console.log(positionId); @@ -39,9 +19,9 @@ describe('Order fetching logic from subgraph', () => { }); it('should return position details by status: OPEN', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); - const userAddress = '0x552AF4aF77b514E0DD1FB5B40A868e7dcE3fD794'; + const userAddress = TEST_USER_ID2; const positions = await parifiSdk.subgraph.getOpenPositionsByUserAddress(userAddress); console.log(positions.length); if (positions.length > 0) { @@ -50,9 +30,9 @@ describe('Order fetching logic from subgraph', () => { }); it('should return position details by status: CLOSED', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); - const userAddress = '0x552AF4aF77b514E0DD1FB5B40A868e7dcE3fD794'; + const userAddress = TEST_USER_ID2; const positions = await parifiSdk.subgraph.getClosedPositionsByUserAddress(userAddress); console.log(positions.length); if (positions.length > 0) { @@ -61,9 +41,9 @@ describe('Order fetching logic from subgraph', () => { }); it('should return position details by status: LIQUIDATED', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); - const userAddress = '0x552AF4aF77b514E0DD1FB5B40A868e7dcE3fD794'; + const userAddress = TEST_USER_ID3; const positions = await parifiSdk.subgraph.getLiquidatedPositionsByUserAddress(userAddress); console.log(positions.length); if (positions.length > 0) { @@ -72,16 +52,16 @@ describe('Order fetching logic from subgraph', () => { }); it('should return price ids for position ids', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); - const positionIds = ['0x08df72fc01f549908150f60f64bd5eb4228fa755d420bd28d3ec2f2957a543f2']; + const positionIds = [TEST_POSITION_ID1, TEST_POSITION_ID2, TEST_POSITION_ID3]; const priceIds = await parifiSdk.subgraph.getPythPriceIdsForPositionIds(positionIds); expect(priceIds.length).toBeGreaterThan(0); }); it('should return position ids available for liquidation', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); const positionsToRefresh = await parifiSdk.subgraph.getPositionsToRefresh(); console.log('positionsToRefresh', positionsToRefresh); @@ -101,10 +81,10 @@ describe('Order fetching logic from subgraph', () => { }); it('should return valid total collateral deposited value from all user positions', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); /// Add an address that has active positions - const userAddress = '0xd60202464e7d923dea9c2b2f5435597e51de2683'; + const userAddress = TEST_USER_ID4; const userPositions = await parifiSdk.subgraph.getAllPositionsByUserAddress(userAddress); if (userPositions.length > 0) { const totalCollateralValueInUsd = await parifiSdk.subgraph.getTotalDepositedCollateralInUsd(userAddress); @@ -113,10 +93,10 @@ describe('Order fetching logic from subgraph', () => { }); it('should return valid total unrealized PNL from all user positions', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); /// Add an address that has active positions - const userAddress = '0xd60202464e7d923dea9c2b2f5435597e51de2683'; + const userAddress = TEST_USER_ID4; const userPositions = await parifiSdk.subgraph.getAllPositionsByUserAddress(userAddress); if (userPositions.length > 0) { const totalNetUnrealizedPnlInUsd = await parifiSdk.subgraph.getTotalUnrealizedPnlInUsd(userAddress); diff --git a/test/subgraph-tests/vaults.test.ts b/test/subgraph-tests/vaults.test.ts index 39f2df0..8b21a8a 100644 --- a/test/subgraph-tests/vaults.test.ts +++ b/test/subgraph-tests/vaults.test.ts @@ -1,37 +1,9 @@ -import { Chain } from '@parifi/references'; -import { PRICE_FEED_DECIMALS, ParifiSdk } from '../../src'; -import { assert } from 'ethers'; -import Decimal from 'decimal.js'; -import { PythConfig, RelayerConfig, RelayerI, RpcConfig, SubgraphConfig } from '../../src/interfaces/classConfigs'; - -const rpcConfig: RpcConfig = { - chainId: Chain.ARBITRUM_MAINNET, -}; - -const subgraphConfig: SubgraphConfig = { - subgraphEndpoint: process.env.SUBGRAPH_ENDPOINT, -}; - -const pythConfig: PythConfig = { - pythEndpoint: process.env.PYTH_SERVICE_ENDPOINT, - username: process.env.PYTH_SERVICE_USERNAME, - password: process.env.PYTH_SERVICE_PASSWORD, - isStable: true, -}; - -const gelatoConfig: RelayerI = { - apiKey: process.env.GELATO_KEY, -}; - -const relayerConfig: RelayerConfig = { - gelatoConfig: gelatoConfig, -}; - -const parifiSdk = new ParifiSdk(rpcConfig, subgraphConfig, relayerConfig, pythConfig); +import { getParifiSdkInstanceForTesting } from '..'; +import { TEST_USER_ID1, TEST_VAULT_ID1 } from '../common/constants'; describe('Vault fetching logic from subgraph', () => { it('should return correct vault details', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); const vaults = await parifiSdk.subgraph.getAllVaults(); console.log('vaults', vaults); @@ -40,7 +12,7 @@ describe('Vault fetching logic from subgraph', () => { }); it('should return correct Total Pool Value', async () => { - await parifiSdk.init(); + const parifiSdk = await getParifiSdkInstanceForTesting(); const data = await parifiSdk.subgraph.getTotalPoolsValue(); console.log(data); @@ -48,24 +20,24 @@ describe('Vault fetching logic from subgraph', () => { }); it('should return correct user vault data', async () => { - await parifiSdk.init(); - const data = await parifiSdk.subgraph.getUserVaultDataByChain('0x30f06f86F107f9523f5b91A8E8AEB602b7b260BD'); + const parifiSdk = await getParifiSdkInstanceForTesting(); + const data = await parifiSdk.subgraph.getUserVaultDataByChain(TEST_USER_ID1); console.log(data); expect(data.length).not.toBe(0); }); it('should return correct user total pools vaule', async () => { - await parifiSdk.init(); - const data = await parifiSdk.subgraph.getUserTotalPoolsValue('0x30f06f86F107f9523f5b91A8E8AEB602b7b260BD'); + const parifiSdk = await getParifiSdkInstanceForTesting(); + const data = await parifiSdk.subgraph.getUserTotalPoolsValue(TEST_USER_ID1); console.log(data); expect(data.myTotalPoolValue).not.toBe(0); }); it('should return correct APR details', async () => { - await parifiSdk.init(); - const vaultId = '0x13a78809528b02ad5e7c42f39232d332761dfb1d'; + const parifiSdk = await getParifiSdkInstanceForTesting(); + const vaultId = TEST_VAULT_ID1; const data = await parifiSdk.subgraph.getVaultApr(vaultId); console.log(data); });