@nemoprotocol/points-sdk
v0.1.1-beta.2
Published
## Table of Contents
Downloads
3
Readme
NEMO Protocol SDK Documentation
Table of Contents
Overview
The NEMO Protocol SDK provides core functionality for querying user positions, calculating market values, and managing yield distributions in the NEMO protocol.
Key Features
- Position Query: Query all positions for any Sui address
- Holder Statistics: Get PT, YT, LP holder counts and position quantities
- Market Value Calculation: Calculate current market values in SUI or underlying assets
- Yield Management: Query and claim available yield
- Pool Information: Get comprehensive pool statistics and market data
- Liquidity Management: Add and remove liquidity positions with transaction execution
Installation
Package Installation
npm install @nemoprotocol/contract-sdk
# or
yarn add @nemoprotocol/contract-sdk
# or
pnpm add @nemoprotocol/contract-sdkEnvironment Configuration
# Build-time configuration
API_BASE_URL=https://api.nemoprotocol.com npm run build
# Development configuration (.env file)
API_BASE_URL=https://api.nemoprotocol.comSDK Initialization
import { PositionQuery, PoolQuery, AddLiquidityAction } from '@nemoprotocol/contract-sdk'
import { SuiClient, getFullnodeUrl } from '@mysten/sui/client'
// Initialize query classes
const positionQuery = new PositionQuery({
network: 'mainnet', // or 'testnet', 'devnet', 'localnet'
rpcUrl: 'https://sui-mainnet.mystenlabs.com' // optional
})
const poolQuery = new PoolQuery()
// Initialize action class for transaction execution
const suiClient = new SuiClient({ url: getFullnodeUrl('mainnet') })
const liquidityAction = new AddLiquidityAction({
suiClient,
privateKeyHex: 'your-private-key-hex' // without 0x prefix or with it
})Core Features
1. Position Query
Query all positions for a specific Sui address in the NEMO protocol.
LP Position Query
const lpPositions = await positionQuery.queryLpPositions({
address: '0x...', // user address
positionTypes: [
'0x...::market::LpPosition<0x...::coin::SUI>',
'0x...::market::LpPosition<0x...::coin::USDC>'
],
maturity: '2024-12-31', // optional filter
marketStateId: '0x...' // optional filter
})
// Response format:
// [
// {
// id: { id: '0x...' },
// name: 'LP-SUI-2024-12-31',
// expiry: '2024-12-31',
// lpAmount: '1000000000',
// description: 'LP position for SUI',
// marketStateId: '0x...'
// }
// ]PY Position Query
const pyPositions = await positionQuery.queryPyPositions({
address: '0x...', // user address
positionTypes: [
'0x...::py_state::PyState<0x...::coin::SUI>',
'0x...::py_state::PyState<0x...::coin::USDC>'
],
maturity: '2024-12-31', // optional filter
pyStateId: '0x...' // optional filter
})
// Response format:
// [
// {
// id: '0x...',
// maturity: '2024-12-31',
// ptBalance: '500000000',
// ytBalance: '300000000',
// pyStateId: '0x...'
// }
// ]2. Holder Statistics
Get users holding different asset types (PT, YT, LP) and their position quantities.
PT/YT Holder Count
const holdersCount = await positionQuery.queryPyPositionHoldersCount({
positionTypes: [
'0x...::py_state::PyState<0x...::coin::SUI>',
'0x...::py_state::PyState<0x...::coin::USDC>'
],
maturity: '2024-12-31',
pyStateId: '0x...',
pageSize: 50 // optional
})
console.log('PT Holders:', holdersCount.ptHolders)
console.log('YT Holders:', holdersCount.ytHolders)
console.log('Total Holders:', holdersCount.totalHolders)
console.log('Holders by Type:', holdersCount.holdersByType)
console.log('Total Positions:', holdersCount.totalPositions)LP Holder Count
const lpHoldersCount = await positionQuery.queryLpPositionHoldersCount({
positionTypes: [
'0x...::market::LpPosition<0x...::coin::SUI>',
'0x...::market::LpPosition<0x...::coin::USDC>'
],
maturity: '2024-12-31',
marketStateId: '0x...',
pageSize: 50 // optional
})
console.log('LP Holders:', lpHoldersCount.totalHolders)
console.log('Holders by Type:', lpHoldersCount.holdersByType)
console.log('Total Positions:', lpHoldersCount.totalPositions)3. Market Value Calculation
Calculate and display current market values of user positions (priced in SUI or underlying assets).
Yield Query
const yieldResult = await positionQuery.queryYield({
address: '0x...',
ytBalance: '1000000000',
pyPositions: [
{
id: '0x...',
maturity: '2024-12-31',
ptBalance: '500000000',
ytBalance: '300000000',
pyStateId: '0x...'
}
],
receivingType: 'sy', // or 'underlying'
config: {
nemoContractId: '0x...',
version: '1.0.0',
coinType: '0x...::coin::SUI',
pyStateId: '0x...',
syCoinType: '0x...::sy_coin::SyCoin<0x...::coin::SUI>',
yieldFactoryConfigId: '0x...',
marketStateId: '0x...',
underlyingCoinType: '0x...::coin::SUI',
underlyingProtocol: 'Scallop',
priceOracleConfigId: '0x...',
oraclePackageId: '0x...',
oracleTicket: '0x...',
oracleVoucherPackageId: '0x...'
}
})
console.log('Output Value:', yieldResult.outputValue)
console.log('Output Amount:', yieldResult.outputAmount)4. Rewards query
Query and claim available yield rewards in the NEMO protocol.
// Query rewards for multiple reward metrics
const rewards = await positionQuery.queryRewards({
address: '0x...', // user address
config: {
nemoContractId: '0x...',
version: '0x...',
marketStateId: '0x...',
// other required config fields
},
lpPositions: [
{
id: { id: '0x...' },
name: 'LP-SUI-2024-12-31',
expiry: '2024-12-31',
lpAmount: '1000000000',
description: 'LP position for SUI',
marketStateId: '0x...'
}
],
rewardMetrics: [
{
tokenType: '0x...::coin::SUI',
syCoinType: '0x...::sy_coin::SyCoin<0x...::coin::SUI>',
tokenLogo: 'https://...',
dailyEmission: '1000000000',
tokenPrice: '1.23',
tokenName: 'SUI',
decimal: '9'
},
{
tokenType: '0x...::coin::USDC',
syCoinType: '0x...::sy_coin::SyCoin<0x...::coin::USDC>',
tokenLogo: 'https://...',
dailyEmission: '500000000',
tokenPrice: '1.00',
tokenName: 'USDC',
decimal: '6'
}
]
});
// Response format:
// [
// {
// coinType: '0x...::coin::SUI',
// coinName: 'SUI',
// amount: '1.234567890'
// },
// {
// coinType: '0x...::coin::USDC',
// coinName: 'USDC',
// amount: '100.123456'
// }
// ]5. Pool Information
Query basic information and statistics for different pools.
Pool Query
const pools = await poolQuery.queryPools()
// Response format:
// [
// {
// id: '0x...',
// tvl: '1000000000000',
// tvlRateChange: '5.2',
// coinLogo: 'https://...',
// maturity: '2024-12-31',
// startTime: '2024-01-01',
// coinName: 'SUI',
// coinType: '0x...::coin::SUI',
// ptTokenType: '0x...::pt_coin::PtCoin<0x...::coin::SUI>',
// nemoContractId: '0x...',
// boost: '1.5',
// provider: 'Scallop',
// providerLogo: 'https://...',
// cap: '10000000000000',
// marketStateId: '0x...',
// syCoinType: '0x...::sy_coin::SyCoin<0x...::coin::SUI>',
// underlyingCoinType: '0x...::coin::SUI',
// providerMarket: '0x...',
// providerVersion: '1.0.0',
// priceOracleConfigId: '0x...',
// decimal: '9',
// underlyingApy: '8.5',
// coinPrice: '1.2',
// underlyingPrice: '1.2',
// pyStateId: '0x...',
// syStateId: '0x...',
// conversionRate: '1.0',
// marketFactoryConfigId: '0x...',
// swapFeeForLpHolder: '0.003',
// underlyingCoinName: 'SUI',
// underlyingCoinLogo: 'https://...',
// version: '1.0.0',
// perPoints: '1000000',
// oraclePackageId: '0x...',
// oracleTicket: '0x...',
// oracleVoucherPackageId: '0x...',
// yieldTokenType: '0x...::yt_coin::YtCoin<0x...::coin::SUI>',
// tokenRegistryState: '0x...',
// ptPrice: '0.95',
// ptTvl: '500000000000',
// syTvl: '500000000000',
// marketState: {
// marketCap: '1000000000000',
// totalSy: '500000000000',
// lpSupply: '1000000000000',
// totalPt: '500000000000',
// rewardMetrics: [...]
// },
// scaledPtApy: '12.5',
// scaledUnderlyingApy: '8.5',
// feeApy: '2.0',
// sevenAvgUnderlyingApy: '8.2',
// sevenAvgUnderlyingApyRateChange: '0.3',
// ytPrice: '0.15',
// lpPrice: '1.0',
// ytTokenLogo: 'https://...',
// ptTokenLogo: 'https://...',
// lpTokenLogo: 'https://...',
// ytReward: '150000000',
// underlyingProtocol: 'Scallop',
// yieldFactoryConfigId: '0x...',
// pyPositionTypeList: ['0x...::py_state::PyState<0x...::coin::SUI>'],
// marketPositionTypeList: ['0x...::market::LpPosition<0x...::coin::SUI>'],
// lpPriceRateChange: '2.1',
// ptPriceRateChange: '-1.5',
// ytPriceRateChange: '5.2',
// incentiveApy: '3.0',
// incentives: [...],
// poolApy: '15.5',
// tradeStatus: 'active'
// }
// ]6. Liquidity Management
Execute liquidity-related transactions including adding and removing liquidity positions.
Add Liquidity
// Add liquidity to a pool
const addResult = await liquidityAction.addLiquidity({
decimal: 9,
addType: 'SY', // 'SY' | 'TOKEN' | 'PT'
slippage: '0.01', // 1% slippage
lpValue: '1000000000', // Amount in base units
coinType: '0x...::coin::SUI',
conversionRate: '1.0',
addValue: '1000000000',
tokenType: 0, // 0 for SY, 1 for TOKEN, 2 for PT
action: 'mint', // 'mint' | 'swap'
// Configuration objects
coinConfig: {
nemoContractId: '0x...',
version: '1.0.0',
coinType: '0x...::coin::SUI',
pyStateId: '0x...',
syCoinType: '0x...::sy_coin::SyCoin<0x...::coin::SUI>',
yieldFactoryConfigId: '0x...',
marketStateId: '0x...',
underlyingCoinType: '0x...::coin::SUI',
underlyingProtocol: 'Scallop',
priceOracleConfigId: '0x...',
oraclePackageId: '0x...',
oracleTicket: '0x...',
oracleVoucherPackageId: '0x...'
},
marketStateData: {
// Market state object from pool query
},
coinData: [
{
coinType: '0x...::coin::SUI',
balance: '1000000000',
coinObjectId: '0x...'
}
],
pyPositionData: {
// PY position data object
},
lpPositions: [
{
id: { id: '0x...' },
name: 'LP-SUI-2024-12-31',
expiry: '2024-12-31',
lpAmount: '1000000000',
description: 'LP position for SUI',
marketStateId: '0x...'
}
],
// Optional parameters
vaultId: '0x...', // optional
insufficientBalance: false
})
// Check result
if (addResult.success) {
console.log('Transaction successful:', addResult.transactionHash)
console.log('Transaction data:', addResult.data)
} else {
console.error('Transaction failed:', addResult.error)
}Remove Liquidity
// Remove liquidity from a position
const removeResult = await liquidityAction.removeLiquidity({
lpAmount: '500000000', // Amount to remove
slippage: '0.01', // 1% slippage
ytBalance: '300000000',
action: 'swap', // 'swap' | 'redeem'
receivingType: 'underlying', // 'underlying' | 'sy'
// Configuration objects
coinConfig: {
nemoContractId: '0x...',
version: '1.0.0',
coinType: '0x...::coin::SUI',
pyStateId: '0x...',
syCoinType: '0x...::sy_coin::SyCoin<0x...::coin::SUI>',
yieldFactoryConfigId: '0x...',
marketStateId: '0x...',
underlyingCoinType: '0x...::coin::SUI',
underlyingProtocol: 'Scallop',
priceOracleConfigId: '0x...',
oraclePackageId: '0x...',
oracleTicket: '0x...',
oracleVoucherPackageId: '0x...'
},
lpPositions: [
{
id: { id: '0x...' },
name: 'LP-SUI-2024-12-31',
expiry: '2024-12-31',
lpAmount: '1000000000',
description: 'LP position for SUI',
marketStateId: '0x...'
}
],
pyPositions: [
{
id: '0x...',
maturity: '2024-12-31',
ptBalance: '500000000',
ytBalance: '300000000',
pyStateId: '0x...'
}
],
marketState: {
marketCap: '1000000000000',
totalSy: '500000000000',
lpSupply: '1000000000000',
totalPt: '500000000000',
rewardMetrics: []
},
// Optional parameters
vaultId: '0x...', // optional
minSyOut: '480000000', // minimum SY output
ptCoins: [
{
coinType: '0x...::pt_coin::PtCoin<0x...::coin::SUI>',
balance: '500000000',
coinObjectId: '0x...'
}
],
minValue: '480000000',
isSwapPt: false
})
// Check result
if (removeResult.success) {
console.log('Transaction successful:', removeResult.transactionHash)
console.log('Transaction data:', removeResult.data)
} else {
console.error('Transaction failed:', removeResult.error)
}Error Handling
try {
const result = await liquidityAction.addLiquidity(params)
if (!result.success) {
// Handle business logic errors
console.error('Business error:', result.error)
// Common error scenarios:
// - Insufficient balance
// - Slippage too high
// - Invalid parameters
// - Market not active
}
} catch (error) {
// Handle unexpected errors
console.error('Unexpected error:', error)
}Utility Methods
// Get current wallet address
const walletAddress = liquidityAction.getAddress()
console.log('Wallet address:', walletAddress)
// Get Sui client instance
const client = liquidityAction.getSuiClient()API Reference
PositionQuery Class
Constructor
new PositionQuery(config: PositionQueryConfig)Parameters:
config.network: Network type ('mainnet' | 'testnet' | 'devnet' | 'localnet')config.rpcUrl: Custom RPC URL (optional)
Methods
queryLpPositions()
async queryLpPositions(options: {
address: string;
positionTypes: string[];
maturity?: string;
marketStateId?: string;
}): Promise<LpPosition[]>queryPyPositions()
async queryPyPositions(options: {
address: string;
positionTypes: string[];
maturity?: string;
pyStateId?: string;
}): Promise<PyPosition[]>queryPyPositionHoldersCount()
async queryPyPositionHoldersCount(options: {
positionTypes: string[];
maturity?: string;
pyStateId?: string;
pageSize?: number;
}): Promise<{
ptHolders: number;
ytHolders: number;
totalHolders: number;
holdersByType: Record<string, { ptHolders: number; ytHolders: number }>;
totalPositions: number;
}>queryLpPositionHoldersCount()
async queryLpPositionHoldersCount(options: {
positionTypes: string[];
maturity?: string;
marketStateId?: string;
pageSize?: number;
}): Promise<{
totalHolders: number;
holdersByType: Record<string, number>;
totalPositions: number;
}>queryYield()
async queryYield(params: QueryYieldParams): Promise<{
outputValue: string;
outputAmount: string;
}>PoolQuery Class
Constructor
new PoolQuery()Methods
queryPools()
async queryPools(): Promise<PortfolioItem[]>AddLiquidityAction Class
Constructor
new AddLiquidityAction(config: AddLiquidityActionConfig)Parameters:
config.suiClient: SuiClient instance for blockchain interactionconfig.privateKeyHex: Private key in hexadecimal format (with or without 0x prefix)
Methods
addLiquidity()
async addLiquidity(params: AddLiquidityActionParams): Promise<AddLiquidityActionResult>Parameters:
params.decimal: Number of decimal places for the tokenparams.addType: Type of asset to add ('SY' | 'TOKEN' | 'PT')params.slippage: Maximum slippage tolerance (e.g., '0.01' for 1%)params.lpValue: LP value amount in base unitsparams.coinType: Coin type identifierparams.conversionRate: Conversion rate for the operationparams.addValue: Amount to add in base unitsparams.tokenType: Token type (0 for SY, 1 for TOKEN, 2 for PT)params.action: Action type ('mint' | 'swap')params.coinConfig: Coin configuration objectparams.marketStateData: Market state dataparams.coinData: Array of coin data objectsparams.pyPositionData: PY position dataparams.lpPositions: Array of LP positionsparams.vaultId: Optional vault identifierparams.insufficientBalance: Optional insufficient balance flag
removeLiquidity()
async removeLiquidity(params: RemoveLiquidityActionParams): Promise<AddLiquidityActionResult>Parameters:
params.lpAmount: Amount of LP tokens to removeparams.slippage: Maximum slippage toleranceparams.ytBalance: YT balance amountparams.action: Action type ('swap' | 'redeem')params.receivingType: Type of asset to receive ('underlying' | 'sy')params.coinConfig: Coin configuration objectparams.lpPositions: Array of LP positionsparams.pyPositions: Array of PY positionsparams.marketState: Market state objectparams.vaultId: Optional vault identifierparams.minSyOut: Optional minimum SY outputparams.ptCoins: Optional PT coins arrayparams.minValue: Optional minimum valueparams.isSwapPt: Optional PT swap flag
execute()
async execute(params: AddLiquidityActionParams): Promise<AddLiquidityActionResult>Alias for addLiquidity() method for backward compatibility.
getAddress()
getAddress(): stringReturns the wallet address associated with the private key.
getSuiClient()
getSuiClient(): SuiClientReturns the SuiClient instance used for blockchain interactions.
Type Definitions
PositionQueryConfig
interface PositionQueryConfig {
network?: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
rpcUrl?: string;
}LpPosition
interface LpPosition {
id: { id: string };
name: string;
expiry: string;
lpAmount: string;
description: string;
marketStateId: string;
}PyPosition
interface PyPosition {
id: string;
maturity: string;
ptBalance: string;
ytBalance: string;
pyStateId: string;
}PortfolioItem
interface PortfolioItem {
id: string;
tvl: string;
tvlRateChange: string;
coinLogo: string;
maturity: string;
startTime: string;
coinName: string;
coinType: string;
ptTokenType: string;
nemoContractId: string;
boost: string;
provider: string;
providerLogo: string;
cap: string;
marketStateId: string;
syCoinType: string;
underlyingCoinType: string;
providerMarket: string;
providerVersion: string;
priceOracleConfigId: string;
decimal: string;
underlyingApy: string;
coinPrice: string;
underlyingPrice: string;
pyStateId: string;
syStateId: string;
conversionRate: string;
marketFactoryConfigId: string;
swapFeeForLpHolder: string;
underlyingCoinName: string;
underlyingCoinLogo: string;
version: string;
perPoints: string;
oraclePackageId: string;
oracleTicket: string;
oracleVoucherPackageId: string;
yieldTokenType: string;
tokenRegistryState: string;
ptPrice: string;
ptTvl: string;
syTvl: string;
marketState: MarketState;
scaledPtApy: string;
scaledUnderlyingApy: string;
feeApy: string;
sevenAvgUnderlyingApy: string;
sevenAvgUnderlyingApyRateChange: string;
ytPrice: string;
lpPrice: string;
ytTokenLogo: string;
ptTokenLogo: string;
lpTokenLogo: string;
ytReward: string;
underlyingProtocol: string;
yieldFactoryConfigId: string;
pyPositionTypeList: string[];
marketPositionTypeList: string[];
lpPriceRateChange: string;
ptPriceRateChange: string;
ytPriceRateChange: string;
incentiveApy: string;
incentives: Incentive[];
poolApy: string;
tradeStatus: string;
}AddLiquidityActionConfig
interface AddLiquidityActionConfig {
suiClient: SuiClient;
privateKeyHex: string; // hexadecimal private key (with or without 0x prefix)
}AddLiquidityActionParams
interface AddLiquidityActionParams {
// Basic parameters
decimal: number;
addType: string;
slippage: string;
lpValue: string;
coinType: string;
conversionRate: string;
addValue: string;
tokenType: number;
action: string; // "mint" | "swap"
// Configuration and data
coinConfig: CoinConfig;
marketStateData: any;
coinData: CoinData[];
pyPositionData: any;
lpPositions: LpPosition[];
// Optional parameters
vaultId?: string;
insufficientBalance?: boolean;
}RemoveLiquidityActionParams
interface RemoveLiquidityActionParams {
lpAmount: string;
slippage: string;
vaultId?: string;
minSyOut?: string;
ytBalance: string;
ptCoins?: CoinData[];
coinConfig: CoinConfig;
action: "swap" | "redeem";
lpPositions: LpPosition[];
pyPositions: any[];
minValue?: string | number;
isSwapPt?: boolean;
receivingType?: "underlying" | "sy";
marketState: MarketState;
}AddLiquidityActionResult
interface AddLiquidityActionResult {
success: boolean;
transactionHash?: string;
error?: string;
data?: any;
}CoinConfig
interface CoinConfig {
nemoContractId: string;
version: string;
coinType: string;
pyStateId: string;
syCoinType: string;
yieldFactoryConfigId: string;
marketStateId: string;
underlyingCoinType: string;
underlyingProtocol: string;
priceOracleConfigId: string;
oraclePackageId: string;
oracleTicket: string;
oracleVoucherPackageId: string;
}CoinData
interface CoinData {
coinType: string;
balance: string;
coinObjectId: string;
}MarketState
interface MarketState {
marketCap: string;
totalSy: string;
lpSupply: string;
totalPt: string;
rewardMetrics: any[];
}Document Version: 1.1
Last Updated: [Date]
