@cetusprotocol/dca-sdk
v1.2.5
Published
SDK for cetus dca
Readme
@cetusprotocol/dca-sdk
DCA (Dollar-Cost Averaging) is a low-risk investment strategy that spreads purchases over time. The Cetus DCA SDK helps developers integrate DCA order creation, withdrawal, cancellation, and on-chain queries into Sui applications.
Table of Contents
- Installation
- Initialization
- Core Workflow
- Quote API (Signature)
- Open DCA Order
- Query Orders
- Withdraw Output
- Close Order
- Order Transaction History
- Token Whitelist
- Global Config
- API Reference
Installation
npm: https://www.npmjs.com/package/@cetusprotocol/dca-sdk
npm install @cetusprotocol/dca-sdkInitialization
import { CetusDcaSDK } from '@cetusprotocol/dca-sdk'
// Mainnet with default RPC
const sdk = CetusDcaSDK.createSDK({ env: 'mainnet' })
// Testnet
const sdkTestnet = CetusDcaSDK.createSDK({ env: 'testnet' })
// Custom RPC or Sui client
const sdkCustom = CetusDcaSDK.createSDK({ env: 'mainnet', full_rpc_url: 'YOUR_FULL_NODE_URL' })
// or
const sdkGrpc = CetusDcaSDK.createSDK({ env: 'mainnet', sui_client })Set the transaction sender before building payloads that transfer coins to the user:
const wallet = 'YOUR_WALLET_ADDRESS'
sdk.setSenderAddress(wallet)Core Workflow
Opening a DCA order requires two steps:
- Fetch a signed quote from the Cetus DCA Quote API. The response provides
fee_rate,per_cycle_in_amount_limit,timestamp, andsignature, which the on-chain contract validates before accepting the order. - Build and submit the open-order transaction via
sdk.Dca.dcaOpenOrderPayload().
User wallet ──► Quote API ──► signed quote ──► dcaOpenOrderPayload ──► Sui transactionQuote API (Signature)
Before calling dcaOpenOrderPayload, request a quote from the Cetus backend. The server signs order constraints (input coin, cycle frequency, cycle count, and per-cycle input cap). The contract rejects orders with invalid or expired signatures.
Endpoint
GET https://api-sui.cetus.zone/dca/quoteQuery parameters
| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| in_coin | string | Yes | Full Move type of the input (pay) coin, e.g. 0x2::sui::SUI or normalized long-form address |
| freq | number | Yes | Cycle interval in seconds (must meet on-chain min_cycle_frequency; see Global Config) |
| count | number | Yes | Total number of execution cycles (must meet on-chain min_cycle_count) |
| sender | string | Yes | Sui address of the order creator (same as sdk.setSenderAddress) |
Example request
https://api-sui.cetus.zone/dca/quote?in_coin=0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC&freq=3600&count=2&sender=0xc5cea39da987d8fe16bf0c6db51bfbf4897aef0edf9588e035ae175ac416fdd1Example response
{
"code": 200,
"msg": "Success",
"data": {
"signer": "0x3124f1006b3a48b41648d6dd2beddc26d96beef0d5aa198c2589e3f44e2bcea4",
"coin_type": "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
"fee_rate": 0,
"amount_in_limit_per_cycle": 3000689,
"timestamp": 1780399709,
"signature": "008385eba204435555c4d730bd1723e8ee9d25e8ea9d3dc3727c24263bd2814b544a25ac9193d63991aa0244e89f685e43577787f682cd3beb493e48eaf7ec570997b4eb4448da38141944bd7c2c42cdf63e94b65fac24da132cb732c9bf6d4f30"
}
}Response field mapping
| Quote API field (data) | dcaOpenOrderPayload param | Description |
| --- | --- | --- |
| fee_rate | fee_rate | Protocol fee rate for the order |
| amount_in_limit_per_cycle | per_cycle_in_amount_limit | Maximum input amount allowed per cycle (base units) |
| timestamp | timestamp | Quote expiry timestamp (Unix seconds); must be used before it expires |
| signature | signature | Backend signature authorizing the quote parameters |
Fetch quote in TypeScript
async function fetchDcaQuote(params: {
in_coin_type: string
cycle_frequency: number
cycle_count: number
sender: string
}) {
const url = new URL('https://api-sui.cetus.zone/dca/quote')
url.searchParams.set('in_coin', params.in_coin_type)
url.searchParams.set('freq', String(params.cycle_frequency))
url.searchParams.set('count', String(params.cycle_count))
url.searchParams.set('sender', params.sender)
const res = await fetch(url.toString())
const body = await res.json()
if (body.code !== 200) {
throw new Error(body.msg ?? 'Failed to fetch DCA quote')
}
return body.data
}Note: Quotes are time-bound. Fetch a fresh quote immediately before building the transaction. Reusing an expired
timestamporsignaturewill cause the on-chain call to fail.
Open DCA Order
Parameter overview
| Parameter | Type | Description |
| --- | --- | --- |
| in_coin_type | string | Input coin Move type (coin deposited into the DCA order) |
| out_coin_type | string | Output coin Move type (coin received each cycle via swap) |
| in_coin_amount | string | Total input amount to deposit, in base units (integer string) |
| cycle_frequency | number | Seconds between each swap execution |
| cycle_count | number | Number of cycles; in_coin_amount is split evenly across cycles |
| per_cycle_min_out_amount | string | Minimum acceptable output per cycle (base units); swap reverts if output is below this |
| per_cycle_max_out_amount | string | Maximum acceptable output per cycle (base units); used as slippage upper bound |
| per_cycle_in_amount_limit | string | From quote API amount_in_limit_per_cycle; caps input spent per cycle |
| fee_rate | number | From quote API |
| timestamp | number | From quote API |
| signature | string | From quote API |
Slippage bounds (per_cycle_min/max_out_amount)
These define the acceptable swap output range per cycle. A common approach:
- Compute human-readable input per cycle:
in_coin_amount / 10^inDecimals / cycle_count - Derive expected output using price bounds:
per_cycle_max_out_amount≈cycleInput / minPrice × 10^outDecimals(best case)per_cycle_min_out_amount≈cycleInput / maxPrice × 10^outDecimals(worst case)
Full example
import { d } from '@cetusprotocol/common-sdk'
import Decimal from 'decimal.js'
const wallet = 'YOUR_WALLET_ADDRESS'
sdk.setSenderAddress(wallet)
const in_coin_type = '0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI'
const out_coin_type = '0x26b3bc67befc214058ca78ea9a2690298d731a2d4309485ec3d40198063c4abc::usdc::USDC'
const cycle_count = 4
const cycle_frequency = 3600 // 1 hour
const in_coin_amount = '40000000000' // 40 SUI (9 decimals)
// Step 1: fetch signed quote
const quote = await fetchDcaQuote({
in_coin_type,
cycle_frequency,
cycle_count,
sender: wallet,
})
// Step 2: compute slippage bounds (example: SUI → USDC)
const inDecimals = 9
const outDecimals = 6
const cycleInputHuman = new Decimal(in_coin_amount).div(10 ** inDecimals).div(cycle_count)
const minPrice = 0.83854 // conservative min output price
const maxPrice = 2.172898 // conservative max input price
const per_cycle_max_out_amount = d(cycleInputHuman).div(d(minPrice)).mul(10 ** outDecimals).toFixed(0)
const per_cycle_min_out_amount = d(cycleInputHuman).div(d(maxPrice)).mul(10 ** outDecimals).toFixed(0)
// Step 3: build and submit transaction
const payload = sdk.Dca.dcaOpenOrderPayload({
in_coin_type,
out_coin_type,
in_coin_amount,
cycle_frequency,
cycle_count,
per_cycle_min_out_amount,
per_cycle_max_out_amount,
per_cycle_in_amount_limit: String(quote.amount_in_limit_per_cycle),
fee_rate: quote.fee_rate,
timestamp: quote.timestamp,
signature: quote.signature,
})
const send_key_pair = 'THE_KEY_PAIR_GENERATED_BY_YOUR_PRIVATE_KEY'
const result = await sdk.FullClient.sendTransaction(send_key_pair, payload)Query Orders
List all DCA orders owned by a wallet address:
const wallet = 'YOUR_WALLET_ADDRESS'
const { data: orders, has_next_page } = await sdk.Dca.getDcaOrders(wallet)| Parameter | Type | Description |
| --- | --- | --- |
| wallet_address | string | Sui address of the order owner |
Returns a paginated DataPage<DcaOrder> with fields such as id, in_coin_type, out_coin_type, in_balance, out_balance, cycle_frequency, next_cycle_at, and status.
Withdraw Output
Withdraw accumulated output coin from an active order without closing it:
const payload = await sdk.Dca.withdrawPayload({
order_id: '0xa60c763185a84b87380a0a1e7e677...',
in_coin_type: '0x2::sui::SUI',
out_coin_type: '0x26b3bc67...::usdc::USDC',
})
const result = await sdk.FullClient.sendTransaction(send_key_pair, payload)| Parameter | Type | Description |
| --- | --- | --- |
| order_id | string | On-chain DCA order object ID |
| in_coin_type | string | Input coin type of the order |
| out_coin_type | string | Output coin type of the order |
Batch withdraw:
const payload = await sdk.Dca.withdrawAll([
{ order_id, in_coin_type, out_coin_type },
// ...
])Close Order
Cancel one or more DCA orders and return remaining input/output balances:
const payload = sdk.Dca.dcaCloseOrderPayload([
{
order_id: '0xfc519e9cccf90f4dfdf3008e529...',
in_coin_type: '0x2::sui::SUI',
out_coin_type: '0x26b3bc67...::usdc::USDC',
},
])
const result = await sdk.FullClient.sendTransaction(send_key_pair, payload)| Parameter | Type | Description |
| --- | --- | --- |
| order_id | string | Order object ID to cancel |
| in_coin_type | string | Input coin type |
| out_coin_type | string | Output coin type |
Order Transaction History
Query MakeDealEvent history (per-cycle swap executions) for a given order:
const history = await sdk.Dca.getDcaOrdersMakeDeal('0x45b567654b09d291f3c99566922b7...')| Parameter | Type | Description |
| --- | --- | --- |
| order_id | string | DCA order object ID |
Token Whitelist
When whitelist mode is enabled on-chain, only listed coin types can be used as input and/or output. Query allowed coins with getDcaCoinWhiteList(whitelist_mode):
| whitelist_mode | Behavior |
| --- | --- |
| 0 | Whitelist disabled; returns empty lists |
| 1 | Return input-coin whitelist only |
| 2 | Return output-coin whitelist only |
| 3 | Return both input and output whitelists |
const { in_coin_list, out_coin_list } = await sdk.Dca.getDcaCoinWhiteList(3)Global Config
Read on-chain limits before creating an order:
const config = await sdk.Dca.getDcaGlobalConfig()
// { min_cycle_count, min_cycle_frequency, whitelist_mode }Ensure cycle_count >= min_cycle_count and cycle_frequency >= min_cycle_frequency.
API Reference
| Method | Description |
| --- | --- |
| dcaOpenOrderPayload(params) | Build transaction to open a DCA order |
| dcaCloseOrderPayload(params[]) | Build transaction to cancel one or more orders |
| withdrawPayload(params) | Build transaction to withdraw output coin |
| withdrawAll(params[]) | Build batch withdraw transaction |
| getDcaOrders(wallet_address) | List orders for a wallet |
| getDcaOrdersMakeDeal(order_id) | Query per-cycle execution events |
| getDcaCoinWhiteList(whitelist_mode) | Query token whitelist |
| getDcaGlobalConfig() | Read global DCA configuration |
| getDcaConfigs() | Read deployed package config object IDs |
More About Cetus
License
MIT
