UNPKG

@rholabs/rho-sdk

Version:

Rho Protocol SDK

498 lines (446 loc) 12.7 kB
import * as dotenv from 'dotenv' import { ethers } from 'ethers' import { describe, expect, test } from '@jest/globals' import RhoSDK, { LiquidityOperation, RiskDirection, UserRole } from '../src/v1' import { MarketInfo, marginTotal } from '../src' dotenv.config() const privateKey = process.env.TEST_PRIVATE_KEY || '' let testAddress = '' const waitTimeout = 60000 let sdk: RhoSDK let markets: MarketInfo[] = [] const sleep = (timeout: number) => new Promise((resolve) => setTimeout(resolve, timeout)) beforeAll(async () => { sdk = new RhoSDK({ network: 'testnet', privateKey }) testAddress = sdk.signerAddress markets = await sdk.getActiveMarkets() console.log('Init test SDK, signer address', sdk.signerAddress, ', markets count:', markets.length) }) describe('Common methods', () => { test( 'getBalance', async () => { const balance = await sdk.getBalance(testAddress) expect(balance).toBeGreaterThanOrEqual(0n) }, waitTimeout ) test( 'getNonce', async () => { const nonce = await sdk.getNonce() expect(nonce).toBeGreaterThanOrEqual(0) }, waitTimeout ) }) describe('Check RPC', () => { test( 'Mainnet RPC', async () => { const mainnetSDK = new RhoSDK({ network: 'mainnet' }) const markets = await mainnetSDK.getActiveMarkets() expect(markets.length).toBeGreaterThan(0) }, waitTimeout ) test( 'Testnet RPC', async () => { const markets = await sdk.getActiveMarkets() expect(markets.length).toBeGreaterThan(0) }, waitTimeout ) }) describe('ERC20 methods', () => { test( 'getBalanceOf', async () => { const balance = await sdk.getBalanceOf(markets[0].descriptor.underlying, testAddress) expect(balance).toBeGreaterThanOrEqual(0n) }, waitTimeout ) test( 'getAllowance', async () => { const allowance = await sdk.getAllowance(markets[0].descriptor.underlying, testAddress, testAddress) expect(allowance).toBeGreaterThanOrEqual(0n) }, waitTimeout ) test( 'setAllowance', async () => { const erc20Address = markets[0].descriptor.underlying const balance = await sdk.getBalanceOf(erc20Address, testAddress) const result = await sdk.setAllowance(erc20Address, testAddress, balance) expect(result.hash).toMatch('0x') }, waitTimeout ) }) describe('Oracle service data', () => { test( 'getOraclePackage', async () => { const marketId = markets[0].descriptor.id const oraclePackage = await sdk.getOraclePackage(marketId) expect(oraclePackage).toBeDefined() if (oraclePackage) { expect(oraclePackage.marketId).toBeDefined() expect(oraclePackage.marketId).toBe(marketId) expect(typeof oraclePackage.timestamp).toBe('number') expect(+oraclePackage.indexValue).toBeGreaterThan(0) } }, waitTimeout ) }) describe('View methods', () => { test( 'getActiveMarketIds', async () => { const marketIds = await sdk.getActiveMarketIds() expect(marketIds.length).toBeGreaterThan(0) }, waitTimeout ) test( 'getPortfolioMarketIds', async () => { const marketIds = await sdk.getPortfolioMarketIds({ userAddress: testAddress, offset: 0, limit: 10 }) expect(marketIds.length).toBeGreaterThanOrEqual(0) }, waitTimeout ) test( 'getMarkets', async () => { expect(markets.length).toBeGreaterThan(0) }, waitTimeout ) test( 'getPortfolio', async () => { const portfolio = await sdk.getPortfolio({ userAddress: testAddress, }) expect(portfolio.length).toBeGreaterThanOrEqual(0) }, waitTimeout ) test( 'getMarketPortfolio', async () => { const portfolio = await sdk.getPortfolio({ userAddress: testAddress }) const marketId = portfolio[0].descriptor.id const marketPortfolio = await sdk.getMarketPortfolio({ marketId, userAddress: testAddress }) expect(marketPortfolio.descriptor.id).toBe(marketId) }, waitTimeout ) test( 'getMarginDetails', async () => { const margin = await sdk.getMarginDetails({ marketId: markets[0].descriptor.id, userAddress: testAddress }) expect(margin.initialMarginThreshold).toBeGreaterThanOrEqual(0n) }, waitTimeout ) test( 'getWithdrawableMargin', async () => { const margin = await sdk.getWithdrawableMargin({ marketId: markets[0].descriptor.id, userAddress: testAddress }) expect(margin).toBeGreaterThanOrEqual(0n) }, waitTimeout ) test( 'getLiquidityDistribution', async () => { const liquidityDistribution = await sdk.getPoolLiquidityDistribution({ marketId: markets[0].descriptor.id, futureId: markets[0].futures[0].id }) expect(liquidityDistribution.intervalLiquidity.length).toBeGreaterThan(0) expect(liquidityDistribution.provisionDistribution.total).toBeGreaterThan(0n) expect(liquidityDistribution.currentFutureRate).toBeGreaterThan(-100n) }, waitTimeout ) test( 'getMakerLiquidityDistribution', async () => { const liquidityDistribution = await sdk.getMakerLiquidityDistribution({ userAddress: testAddress, futureId: markets[0].futures[0].id }) expect(liquidityDistribution.intervalLiquidity.length).toBeGreaterThanOrEqual(0) expect(liquidityDistribution.currentFutureRate).toBeGreaterThan(-100n) }, waitTimeout ) test( 'isLiquidatable', async () => { const [market] = markets const isLiquidatable = await sdk.isLiquidatable({ marketId: market.descriptor.id, userAddress: testAddress }) expect(isLiquidatable).toBe(false) }, waitTimeout ) test( 'isProvisionCancellable', async () => { const [market] = markets const isProvisionCancellable = await sdk.isProvisionCancellable({ marketId: market.descriptor.id, userAddress: testAddress }) expect(isProvisionCancellable).toBe(false) }, waitTimeout ) test( 'futuresInfoCloseToMaturityWithoutIndex', async () => { const [market] = markets const futures = await sdk.futuresInfoCloseToMaturityWithoutIndex({ marketId: market.descriptor.id, maturityBufferSeconds: 12 * 24 * 60_60_1000 }) expect(futures.length).toBeGreaterThan(0) }, waitTimeout ) }) describe('Quote methods', () => { test( 'getTradeQuote', async () => { const [market] = markets const [future] = market.futures const quote = await sdk.getTradeQuote({ marketId: market.descriptor.id, futureId: future.id, userAddress: testAddress, notional: 100n * 10n ** market.descriptor.underlyingDecimals }) expect(quote.insufficientLiquidityForPayer).toBe(false) expect(quote.insufficientLiquidityForReceiver).toBe(false) expect(quote.receiverQuote.newMargin.collateral).toBeGreaterThanOrEqual(0n) }, waitTimeout ) test( 'getLiquidityProvisionQuote', async () => { const [market] = markets const [future] = market.futures const quote = await sdk.getLiquidityProvisionQuote({ marketId: market.descriptor.id, futureId: future.id, userAddress: testAddress, operation: LiquidityOperation.PROVIDE, notional: 1n * 10n ** market.descriptor.underlyingDecimals, lowerBound: (10 ** 16).toString(), upperBound: (5 * 10 ** 16).toString() }) expect(quote.totalFutureProvisionPayerDv01).toBeGreaterThanOrEqual(0n) }, waitTimeout ) }) describe('Router', () => { test( 'executeTradeEstimateGas', async () => { const [market] = markets const [future] = market.futures const marketId = market.descriptor.id const futureId = future.id const gas = await sdk.executeTradeEstimateGas({ marketId, futureId, riskDirection: RiskDirection.RECEIVER, notional: 1n * 10n ** market.descriptor.underlyingDecimals, futureRateLimit: 10000n, depositAmount: 0n, }) expect(gas).toBeGreaterThan(0n) }, waitTimeout ) test( 'executeTrade', async () => { const [market] = markets const [future] = market.futures const marketId = market.descriptor.id const futureId = future.id const notional = 1n * 10n ** market.descriptor.underlyingDecimals const tradeQuote = await sdk.getTradeQuote({ marketId: market.descriptor.id, futureId: future.id, userAddress: testAddress, notional }) const selectedQuote = tradeQuote.receiverQuote const futureRateLimit = selectedQuote.tradeInfo.tradeRate + BigInt(0.1 * 10 ** 16) * BigInt(-1) let depositAmount = selectedQuote.newMarginThreshold - marginTotal(selectedQuote.newMargin) if (depositAmount < 0n) { depositAmount = 0n } const trade = await sdk.executeTrade({ marketId, futureId, riskDirection: RiskDirection.RECEIVER, notional, futureRateLimit, depositAmount }) expect(trade.from).toBe(sdk.signerAddress) expect(trade.hash).toMatch('0x') }, waitTimeout ) test( 'executeTrade with custom nonce', async () => { const [market] = markets const [future] = market.futures const marketId = market.descriptor.id const futureId = future.id const notional = 1n * 10n ** market.descriptor.underlyingDecimals const tradeQuote = await sdk.getTradeQuote({ marketId: market.descriptor.id, futureId: future.id, userAddress: testAddress, notional }) const selectedQuote = tradeQuote.receiverQuote const futureRateLimit = selectedQuote.tradeInfo.tradeRate + BigInt(0.1 * 10 ** 16) * BigInt(-1) let depositAmount = selectedQuote.newMarginThreshold - marginTotal(selectedQuote.newMargin) if (depositAmount < 0n) { depositAmount = 0n } const nonce = await sdk.getNonce() expect(nonce).toBeGreaterThan(0) const trade = await sdk.executeTrade({ marketId, futureId, riskDirection: RiskDirection.RECEIVER, notional, futureRateLimit, depositAmount }, { nonce, }) expect(trade.hash).toMatch('0x') await sleep(5000) const nonceAfter = await sdk.getNonce() expect(nonceAfter).toBeGreaterThan(nonce) }, waitTimeout ) test( 'deposit', async () => { const marketId = markets[0].descriptor.id const tx = await sdk.deposit({ marketId, userAddress: sdk.signerAddress, amount: 100n }) expect(tx.hash).toMatch('0x') }, waitTimeout ) test( 'withdraw', async () => { const marketId = markets[0].descriptor.id const marginState = await sdk.getMarginDetails({ marketId, userAddress: testAddress }) const delta = marginState.margin.collateral - marginState.lpMarginThreshold if (delta > 0) { const tx = await sdk.withdraw({ marketId, amount: 100n }) expect(tx.hash).toMatch('0x') } }, waitTimeout ) }) describe('Access Control Manager', () => { const tempWallet = ethers.Wallet.createRandom() test( 'getUsersCount', async () => { const count = await sdk.getUsersCount({ role: UserRole.PROTOCOL_USER }) expect(count).toBeGreaterThan(0) } ) test( 'getUsers', async () => { const limit = 10 const users = await sdk.getUsers({ role: UserRole.PROTOCOL_USER, offset: 0, limit }) expect(users.length).toBe(limit) } ) test( 'hasRole', async () => { const hasRole = await sdk.hasRole({ role: UserRole.PROTOCOL_USER, address: tempWallet.address }) expect(hasRole).toBe(false) } ) test( 'grant and revoke role', async () => { const role = UserRole.PROTOCOL_USER const address = tempWallet.address const grantResult = await sdk.grantRole({ role, address }) expect(grantResult.hash).toMatch('0x') await sleep(5000) const revokeResult = await sdk.revokeRole({ role, address }) expect(revokeResult.hash).toMatch('0x') }, waitTimeout ) })