Saturn v4 is built to be used by programs as much as by people. Every contract is permissionless: a trading bot or an AI agent calls the same methods a wallet does, pays the same fees, and is held to the same on-chain rules. This guide shows the ways a program can make money on Saturn, where it can borrow capital for a trade, and exactly which methods to call.
Everything below runs on Phantasma mainnet (RPC https://pharpc1.phantasma.info/rpc, nexus mainnet) and devnet (https://devnet.phantasma.info/rpc, nexus testnet). A bot needs a Phantasma wallet with KCAL for gas and a little SOUL for new storage keys. Reads are free; writes are signed by the bot's own wallet.
Every trade that borrows capital is atomic: the money has to be back before the transaction ends, or the whole transaction is undone and only the gas is spent.
Every price on Saturn v4 comes from pool reserves that anyone can read for free: saturnrouter and saturnpools views list the pools, return reserves and fees, pick the best pool for a trade and give the raw minimum a swap must meet. A bot quotes a swap off-chain with the same integer math as saturnswap, uses time-weighted prices where a pool is tracked, and can take a 15-second snapshot of every pool and token from the public data API (apiops.saturnx.cc) without any RPC calls.
saturnrouter.getBestPoolForSwapV2() saturnrouter.getPoolFullInfo() saturnrouter.getPoolPrice() saturnrouter.getPoolCountForPair() saturnrouter.getPoolIdForPairAtIndex() saturnrouter.getMinRawForSwap() saturnrouter.getFeeSplitRatios() saturnpools.getActivePoolsData() saturnpools.getAllPoolsData() saturnpools.scaleUp() saturnpools.scaleDown() saturnpools.getScaleFactor() saturnpools.getScaleDivisor() saturnpools.computeAndStoreScaleFactor() saturnpools.getTwapTracked() saturnpools.getTwapCumulativeA() saturnpools.getTwapCumulativeB() saturnpools.getTwapSince() saturnpools.getPoolWithdrawable() saturnpools.getPoolPawned() saturnswap.swap()
saturnflash lets a bot arbitrage two Saturn v4 pools of the same pair with no capital: it borrows the input from saturnliquidity (every pool's reserves), runs both swaps, returns the principal, pays a 0.05% flash fee to the protocol and hands the bot the rest, in one transaction that reverts if there is no profit. saturnarb runs the same two-pool route with the bot's own tokens, charges no flash fee and returns 100% of the profit. Either way a failed attempt costs only gas, so the work is finding and sizing the price gap off-chain.
saturnflash.executeFlashArb() saturnflash.quoteFlashFee() saturnflash.getMaxBorrowable() saturnflash.getFlashFeePer10k() saturnflash.getFlashEnabled() saturnflash.getExecutorTotalProfit() saturnarb.executeArbitrage() saturnarb.getExecutorTotalProfit() saturnpools.getActivePoolsData() saturnrouter.getPoolCountForPair() saturnrouter.getPoolIdForPairAtIndex() saturnrouter.getPoolFullInfo() saturnrouter.getPoolPrice() saturnrouter.getMinRawForSwap() saturnpools.scaleUp() saturnpools.scaleDown() saturnliquidity.getLiquidityAddress()
saturnstakearb lets a bot borrow the idle tokens that holders have staked in saturnholders, arbitrage two Saturn v4 pools of the same pair with them, and return every token in the same transaction. There is no fee and no capital needed: the profit is split, half (rounded down) to the bot and the rest to that token's stakers, and a round trip that does not come back with more than it borrowed reverts, costing only gas. On thin gaps it leaves the bot more than saturnflash, and it pays stakers a yield on top of swap fees without risking their stake, so it is also an easy pitch to a token's holders.
saturnstakearb.executeArb() saturnstakearb.getTotalArbs() saturnstakearb.getTotalHolderProfit() saturnstakearb.getExecutorArbCount() saturnstakearb.getContractVersion() saturnholders.getStakedTokensData() saturnholders.getTotalStaked() saturnholders.flashLendStake() saturnholders.settleArbLoan() saturnholders.getLoanOpen() saturnholders.accrueHolderFee() saturnholders.stake() saturnholders.unstake() saturnholders.claim() saturnholders.getPendingRewards() saturnholders.getLifetimeAccrued() saturnholders.getPledgeLocked() saturnpools.getActivePoolsData() saturnrouter.getPoolCountForPair() saturnrouter.getPoolIdForPairAtIndex() saturnrouter.getPoolFullInfo() saturnrouter.getPoolPrice() saturnrouter.getMinRawForSwap() saturnflash.quoteFlashFee()
saturnvaults lets a bot open a public vault in one base token, take deposits from anyone, and arbitrage with that pooled money through agentArb (two pools) or agentArb3 (three pools). Every trade has to end with more base token than it started, measured on the contract's own balance, or it reverts, so depositors can only gain in base-token terms. The bot earns its fixed fee (1–30%) of each trade's profit, paid out at once. Use it when you have an arbitrage strategy and want more capital than your own, with no flash-loan fee and a public on-chain track record (share price, trade log) that brings in depositors.
saturnvaults.getContractVersion() saturnvaults.createVaultV2() saturnvaults.deposit() saturnvaults.getVaultTotalDeposits() saturnvaults.agentArb() saturnvaults.agentArb3() saturnvaults.getVaultStats() saturnvaults.getAllVaultsStats() saturnvaults.getVaultTrades() saturnvaults.getVaultSharePrice() saturnvaults.getVaultProfitToOthers() saturnvaults.getUserValue() saturnvaults.getUserUnlockAt() saturnvaults.withdrawV2() saturnvaults.setVaultName() saturnvaults.setVaultMinHold() saturnvaults.closeVault() saturnrouter.getPoolCountForPair() saturnrouter.getPoolIdForPairAtIndex() saturnrouter.getPoolFullInfo() saturnrouter.getMinRawForSwap()
saturnmarket is a peer-to-peer market for TAZ loans of 7 to 365 days. The borrower pledges an RA/TAZ Saturn v4 pool they provide; the pool keeps trading and keeps earning the borrower's provider fees. Lenders post binding quotes with the TAZ escrowed, and the borrower accepts one and receives the TAZ in the same transaction. It suits a bot that needs working capital or TAZ inventory for longer than one transaction. It is not a flash loan, and it needs a lender to quote.
saturnmarket.postLoanRequest() saturnmarket.submitQuote() saturnmarket.acceptQuote() saturnmarket.withdrawQuote() saturnmarket.cancelRequest() saturnmarket.getNextRequestId() saturnmarket.getRequestSummary() saturnmarket.getRequestExpiresAt() saturnmarket.getRequestCollateralPoolId() saturnmarket.getRequestQuoteCount() saturnmarket.getRequestQuoteAtIndex() saturnmarket.getQuoteSummary() saturnmarket.getRequestLoanId() saturnmarket.getBorrowerProfile() saturnmarket.getMarketEnabled() saturndexadapt.v4PoolPledgeable() saturndexadapt.getReferencePool() saturndexadapt.v4PoolValueInBase() saturnloans.makePayment() saturnloans.getLoanRemaining() saturnloans.getLoanDueDate() saturnloans.installmentOverdue() saturnloans.getCurrentLtv() saturnloans.getLoanLiquidationFlaggedAt() saturnloans.getLiquidationTwapLtv() saturnloans.flagLiquidation() saturnloans.triggerLiquidation() saturnloans.triggerDefault() saturnloans.getLenderBalance() saturnloans.withdrawLenderBalance() saturnloans.claimRepaymentReward() saturntaz.previewRewardForLoan() saturntaz.getRewardParam() saturntaz.pledgeV4() saturntaz.claimPledgeRewards() saturnlendcfg.getLiquidationThreshold() saturnlendcfg.getMinLoanDuration() saturnlendcfg.getMaxLoanDuration() saturnlendcfg.getOriginationFeeBps() saturnlendcfg.getProtocolFeeShare() saturnlendcfg.getGracePeriod() saturnlendcfg.getMaxLoansPerUser() saturnliquidity.createPool() saturnholders.stake()
Saturn users can leave work on chain for bots (none on mainnet yet, 2026-09-28): limit orders waiting for a price, and TWAMM streams that swap a large amount in chunks over time. Anyone can execute a limit order once its pool pays the owner's minimum, and keeps up to 5% of whatever the fill pays above that minimum. Anyone can fire a stream's next chunk once its pacing time has passed, and keeps up to 5% of that chunk's output. You need no capital, only KCAL for gas and a little SOUL. The work is finding orders and chunks that are due and sending only the ones that will go through. Before you run a bot, check saturnlimit.getActiveOrderCount and saturntwamm.getActiveStreamCount: both are 0 on mainnet today.
saturnlimit.getContractVersion() saturnlimit.getActiveOrdersData() saturnlimit.getActiveOrderIdsByPool() saturnlimit.getActiveOrderCount() saturnlimit.getOrderInfo() saturnlimit.getNextOrderId() saturnlimit.executeOrder() saturnlimit.expireOrder() saturnlimit.placeOrderV2() saturnlimit.cancelOrder() saturntwamm.getContractVersion() saturntwamm.getAllActiveStreamIds() saturntwamm.getActiveStreamsData() saturntwamm.getStreamPoolId() saturntwamm.getStreamTokenIn() saturntwamm.getStreamTokenOut() saturntwamm.getStreamAmountInTotal() saturntwamm.getStreamAmountStreamedSoFar() saturntwamm.getStreamAmountInRemaining() saturntwamm.getStreamStartTime() saturntwamm.getStreamEndTime() saturntwamm.getStreamLastExecutionTime() saturntwamm.getStreamMinChunkSeconds() saturntwamm.getStreamMinOutputPerChunk() saturntwamm.getStreamBountyPer10k() saturntwamm.getStreamFloorMode() saturntwamm.executeStreamingChunk() saturntwamm.placeStreamingOrder() saturntwamm.cancelStream() saturnrouter.getPoolFullInfo() saturnrouter.getMinRawForSwap() saturnpools.getPoolReserveA() saturnpools.getPoolReserveB() saturnpools.getPoolFee() saturnpools.scaleUp() saturnpools.scaleDown()