DCA Module
Dollar-Cost Averaging (DCA) SDK for Astros Aggregator
Features
- ✅ Create DCA orders
- ✅ Cancel DCA orders
- ✅ Query user orders with pagination
- ✅ Get order details with execution history
- ✅ List all orders by status
Usage
1. Create DCA Order
import { createDcaOrder, TimeUnit } from '@naviprotocol/astros-dca-sdk'
const tx = await createDcaOrder(
client,
userAddress,
{
fromCoinType: '0x2::sui::SUI',
toCoinType: '0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX',
depositedAmount: '1500000000',
totalExecutions: 10,
frequency: {
value: 1,
unit: TimeUnit.HOUR
},
priceRange: {
minBuyPrice: 18000000,
maxBuyPrice: 25000000
}
}
)
const testTx = await createDcaOrder(
client,
userAddress,
params,
{
dcaContract: '0xTEST_PACKAGE_ID',
dcaGlobalConfig: '0xTEST_GLOBAL_CONFIG',
dcaRegistry: '0xTEST_REGISTRY'
}
)
Note: All amount fields must be in atomic units. For example:
- 1 SUI = 1000000000 (1 * 10^9)
- 1 USDC = 1000000 (1 * 10^6)
The SDK automatically:
- ✅ Fetches all coins of the specified type
- ✅ Merges multiple coins if needed
- ✅ Checks if balance is sufficient
- ✅ Handles SUI gas coin properly
2. Query User Orders
import { getUserDcaOrders } from '@naviprotocol/astros-dca-sdk'
const result = await getUserDcaOrders('0xUSER_ADDRESS', {
status: 'active',
page: 0,
pageSize: 10
})
console.log('Orders:', result.data)
console.log('Total:', result.pagination.total)
3. Get Order Details
import { getDcaOrderDetails } from '@naviprotocol/astros-dca-sdk'
const order = await getDcaOrderDetails('ORDER_ID')
console.log('Order status:', order.status)
console.log('From:', order.fromCoinSymbol, order.fromCoinLogoURI)
console.log('To:', order.toCoinSymbol, order.toCoinLogoURI)
console.log('Progress:', order.progress.percentage * 100, '%')
console.log('Executions:', order.fills.length)
order.fills.forEach((fill, i) => {
console.log(`Cycle ${fill.cycleNumber}:`, {
amountIn: fill.amountIn,
amountOut: fill.amountOut,
price: fill.priceOutPerIn,
status: fill.status,
txDigest: fill.txDigest
})
})
4. List All Orders by Status
import { listDcaOrders } from '@naviprotocol/astros-dca-sdk'
const orders = await listDcaOrders()
console.log('Active:', orders.active.length)
console.log('Completed:', orders.completed.length)
console.log('Canceled:', orders.canceled.length)
const activeOrders = await listDcaOrders({ status: 'active' })
5. Cancel DCA Order
import { cancelDcaOrder, getUserDcaOrders } from '@naviprotocol/astros-dca-sdk'
const orders = await getUserDcaOrders(userAddress, { status: 'active' })
const order = orders.data[0]
if (!order.receiptId) {
throw new Error(
'Receipt ID not available. Order may have been created before this feature was added.'
)
}
const tx = await cancelDcaOrder(
{
fromCoinType: order.fromCoinType,
toCoinType: order.toCoinType
},
order.receiptId,
userAddress
)
const testTx = await cancelDcaOrder(
{
fromCoinType: order.fromCoinType,
toCoinType: order.toCoinType
},
order.receiptId,
userAddress,
{
dcaContract: '0xTEST_PACKAGE_ID',
dcaGlobalConfig: '0xTEST_GLOBAL_CONFIG',
dcaRegistry: '0xTEST_REGISTRY'
}
)
const result = await suiClient.signAndExecuteTransaction({
transaction: tx,
signer: keypair
})
Important Notes:
- The
receiptId is provided by the backend API in all order query responses
- No additional blockchain queries are needed
- If
receiptId is null, the order was created before this feature was implemented
Configuration
DCA Options (Testing)
The SDK uses production contract addresses by default. You can override them for testing using the optional dcaOptions parameter:
import { DcaOptions } from '@naviprotocol/astros-aggregator-sdk'
const testOptions: DcaOptions = {
dcaContract: '0xTEST_PACKAGE_ID',
dcaGlobalConfig: '0xTEST_GLOBAL_CONFIG',
dcaRegistry: '0xTEST_REGISTRY'
}
const tx1 = await createDcaOrder(client, userAddress, params, testOptions)
const tx2 = await cancelDcaOrder(params, receiptId, address, testOptions)
Production vs Testing:
| Production | No dcaOptions parameter (default) |
| Testing | Pass dcaOptions with test contract |
Available in:
- ✅
createDcaOrder()
- ✅
cancelDcaOrder()
Note: Query functions (getUserDcaOrders, getDcaOrderDetails, etc.) use the backend API, which is configured separately via updateConfig({ aggregatorBaseUrl }) in the Aggregator module.
Understanding Order ID vs Receipt ID
When you create a DCA order, two objects are created on-chain:
Why two IDs?
- The Receipt is your ownership proof - only the Receipt holder can cancel the order
- This follows Sui's object ownership model for security
- The backend automatically extracts and stores both IDs for your convenience
Types
Order Response
All order queries return orders with the following structure:
{
id: string
status: 'active' | 'completed' | 'canceled'
orderNum: number
user: string
receiptId: string | null
fromCoinType: string
fromCoinSymbol: string
fromCoinLogoURI: string
toCoinType: string
toCoinSymbol: string
toCoinLogoURI: string
depositedAmount: string
originalAmountPerCycle: string
minAmountOut: string
maxAmountOut: string
gap: { value: number, unit: 'minute' | 'hour' | 'day' | 'week' | 'month' }
cliff: { value: number, unit: 'minute' | 'hour' | 'day' | 'week' | 'month' }
progress: {
succeededInput: string
depositedInput: string
percentage: number
}
priceOutPerIn: { min: number | null, max: number | null }
priceInPerOut: { min: number | null, max: number | null }
createdAt: string
updatedAt: string
createTxDigest: string | null
cancelTxDigest: string | null
}
Order Details
When calling getDcaOrderDetails(), you also get execution history and additional fields:
{
...orderFields,
currentCycle: number
totalSucceeded: number
lastExecutionStatus: string | null
fills: [
{
cycleNumber: number
createdAt: string
status: string
amountIn: string
amountOut: string
protocolFeeCharged: string
priceOutPerIn: number | null
priceInPerOut: number | null
txDigest: string | null
}
]
}
Configuration
The SDK uses the default Astros aggregator API endpoint. If you need to customize it:
import { updateConfig } from '@naviprotocol/astros-aggregator-sdk'
updateConfig({
aggregatorBaseUrl: 'https://open-aggregator-api.naviprotocol.io/find_routes'
})
Note: DCA query functions automatically derive the API base URL from the aggregator configuration.