From 4ead7f650e5eacabbbc7be532a64675b4cbb1fc4 Mon Sep 17 00:00:00 2001 From: Rui Date: Sat, 14 Jun 2025 01:25:29 +0800 Subject: [PATCH 1/7] codegen --- .../machine/TradingStateMachine+Candles.kt | 1 - .../machine/TradingStateMachine+Wallet.kt | 18 -------- .../state/supervisor/Configs.kt | 4 ++ .../codegen/IndexerFundingPaymentResponse.kt | 32 ++++++++++++++ .../IndexerFundingPaymentResponseObject.kt | 44 +++++++++++++++++++ .../IndexerPerpetualMarketResponseObject.kt | 4 +- .../codegen/IndexerPnlTicksResponseObject.kt | 4 -- .../app/manager/v2/V4TransactionTests.kt | 2 +- .../functional/vault/VaultTests.kt | 4 -- .../TradingStateMachine+TestUtils.kt | 22 +++++++++- .../tests/payloads/VaultMocks.kt | 2 - 11 files changed, 104 insertions(+), 33 deletions(-) create mode 100644 src/commonMain/kotlin/indexer/codegen/IndexerFundingPaymentResponse.kt create mode 100644 src/commonMain/kotlin/indexer/codegen/IndexerFundingPaymentResponseObject.kt diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+Candles.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+Candles.kt index fa9d2c562..d4ef56d21 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+Candles.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+Candles.kt @@ -9,7 +9,6 @@ import indexer.codegen.IndexerCandleResponseObject import kollections.iListOf import kollections.toIList -// Called in test code only internal fun TradingStateMachine.candles(payload: String): StateChanges { val json = parser.decodeJsonObject(payload) return if (json != null) { diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+Wallet.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+Wallet.kt index 5f7a6ea88..de6ea6795 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+Wallet.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+Wallet.kt @@ -147,15 +147,6 @@ internal fun TradingStateMachine.onChainUserStats(payload: String): StateChanges } } -internal fun TradingStateMachine.fills(payload: String, subaccountNumber: Int): StateChanges { - val json = parser.decodeJsonObject(payload) - return if (json != null) { - receivedFills(json, subaccountNumber) - } else { - StateChanges.noChange - } -} - internal fun TradingStateMachine.receivedFills( payload: Map, subaccountNumber: Int, @@ -176,15 +167,6 @@ internal fun TradingStateMachine.receivedFills( } } -internal fun TradingStateMachine.transfers(payload: String, subaccountNumber: Int): StateChanges { - val json = parser.decodeJsonObject(payload) - return if (json != null) { - receivedTransfers(json, subaccountNumber) - } else { - StateChanges.noChange - } -} - internal fun TradingStateMachine.receivedTransfers( payload: Map, subaccountNumber: Int, diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/supervisor/Configs.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/supervisor/Configs.kt index a2e2d293d..411512b63 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/supervisor/Configs.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/supervisor/Configs.kt @@ -84,6 +84,7 @@ data class SubaccountConfigs( val retrieveFills: Boolean, val retrieveTransfers: Boolean, val retrieveHistoricalPnls: Boolean, + val retrieveFundingPayments: Boolean, val subscribeToSubaccount: Boolean, val useParentSubaccount: Boolean, var notifications: List = @@ -99,6 +100,7 @@ data class SubaccountConfigs( retrieveFills = true, retrieveTransfers = true, retrieveHistoricalPnls = true, + retrieveFundingPayments = true, subscribeToSubaccount = true, useParentSubaccount = false, ) @@ -106,6 +108,7 @@ data class SubaccountConfigs( retrieveFills = true, retrieveTransfers = true, retrieveHistoricalPnls = true, + retrieveFundingPayments = true, subscribeToSubaccount = true, useParentSubaccount = true, ) @@ -113,6 +116,7 @@ data class SubaccountConfigs( retrieveFills = false, retrieveTransfers = false, retrieveHistoricalPnls = false, + retrieveFundingPayments = false, subscribeToSubaccount = true, useParentSubaccount = false, ) diff --git a/src/commonMain/kotlin/indexer/codegen/IndexerFundingPaymentResponse.kt b/src/commonMain/kotlin/indexer/codegen/IndexerFundingPaymentResponse.kt new file mode 100644 index 000000000..3a472119a --- /dev/null +++ b/src/commonMain/kotlin/indexer/codegen/IndexerFundingPaymentResponse.kt @@ -0,0 +1,32 @@ +/** + * Indexer API + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: v1.0.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ +package indexer.codegen + +import kotlinx.serialization.Serializable +import kotlin.js.JsExport + +/** + * + * @param pageSize + * @param totalResults + * @param offset + * @param fundingPayments + */ +@JsExport +@Serializable +data class IndexerFundingPaymentResponse( + + val pageSize: kotlin.Int? = null, + val totalResults: kotlin.Int? = null, + val offset: kotlin.Int? = null, + val fundingPayments: kotlin.Array? = null +) diff --git a/src/commonMain/kotlin/indexer/codegen/IndexerFundingPaymentResponseObject.kt b/src/commonMain/kotlin/indexer/codegen/IndexerFundingPaymentResponseObject.kt new file mode 100644 index 000000000..053c33559 --- /dev/null +++ b/src/commonMain/kotlin/indexer/codegen/IndexerFundingPaymentResponseObject.kt @@ -0,0 +1,44 @@ +/** + * Indexer API + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: v1.0.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ +package indexer.codegen + +import kotlinx.serialization.Serializable +import kotlin.js.JsExport + +/** + * + * @param createdAt + * @param createdAtHeight + * @param perpetualId + * @param ticker + * @param oraclePrice + * @param size + * @param side + * @param rate + * @param payment + * @param subaccountNumber + */ +@JsExport +@Serializable +data class IndexerFundingPaymentResponseObject( + + val createdAt: IndexerIsoString? = null, + val createdAtHeight: kotlin.String? = null, + val perpetualId: kotlin.String? = null, + val ticker: kotlin.String? = null, + val oraclePrice: kotlin.String? = null, + val size: kotlin.String? = null, + val side: kotlin.String? = null, + val rate: kotlin.String? = null, + val payment: kotlin.String? = null, + val subaccountNumber: kotlin.String? = null +) diff --git a/src/commonMain/kotlin/indexer/codegen/IndexerPerpetualMarketResponseObject.kt b/src/commonMain/kotlin/indexer/codegen/IndexerPerpetualMarketResponseObject.kt index cf67dc538..794bd6e45 100644 --- a/src/commonMain/kotlin/indexer/codegen/IndexerPerpetualMarketResponseObject.kt +++ b/src/commonMain/kotlin/indexer/codegen/IndexerPerpetualMarketResponseObject.kt @@ -37,6 +37,7 @@ import kotlin.js.JsExport * @param openInterestLowerCap * @param openInterestUpperCap * @param baseOpenInterest + * @param defaultFundingRate1H */ @JsExport @Serializable @@ -62,5 +63,6 @@ data class IndexerPerpetualMarketResponseObject( val marketType: IndexerPerpetualMarketType? = null, val openInterestLowerCap: kotlin.String? = null, val openInterestUpperCap: kotlin.String? = null, - val baseOpenInterest: kotlin.String? = null + val baseOpenInterest: kotlin.String? = null, + val defaultFundingRate1H: kotlin.String? = null ) diff --git a/src/commonMain/kotlin/indexer/codegen/IndexerPnlTicksResponseObject.kt b/src/commonMain/kotlin/indexer/codegen/IndexerPnlTicksResponseObject.kt index 6797e561a..d4eeaa304 100644 --- a/src/commonMain/kotlin/indexer/codegen/IndexerPnlTicksResponseObject.kt +++ b/src/commonMain/kotlin/indexer/codegen/IndexerPnlTicksResponseObject.kt @@ -16,8 +16,6 @@ import kotlin.js.JsExport /** * - * @param id - * @param subaccountId * @param equity * @param totalPnl * @param netTransfers @@ -29,8 +27,6 @@ import kotlin.js.JsExport @Serializable data class IndexerPnlTicksResponseObject( - val id: kotlin.String? = null, - val subaccountId: kotlin.String? = null, val equity: kotlin.String? = null, val totalPnl: kotlin.String? = null, val netTransfers: kotlin.String? = null, diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/app/manager/v2/V4TransactionTests.kt b/src/commonTest/kotlin/exchange.dydx.abacus/app/manager/v2/V4TransactionTests.kt index 28e1cb5b2..1faccaeae 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/app/manager/v2/V4TransactionTests.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/app/manager/v2/V4TransactionTests.kt @@ -43,7 +43,7 @@ class V4TransactionTests : NetworkTests() { stateMachine = v4Adapter!!.stateMachine, helper = v4Adapter!!.networkHelper, analyticsUtils = v4Adapter!!.analyticsUtils, - configs = SubaccountConfigs(true, true, true, true, false), + configs = SubaccountConfigs(true, true, true, true, true, false), accountAddress = testCosmoAddress, subaccountNumber = 0, ) diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultTests.kt b/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultTests.kt index 9e5b3291c..f0bcb7537 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultTests.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultTests.kt @@ -190,14 +190,12 @@ class VaultTests { ticker = "BTC-USD", historicalPnl = arrayOf( IndexerPnlTicksResponseObject( - id = "1", equity = "10500.0", totalPnl = "500.0", netTransfers = "0.0", createdAt = Instant.fromEpochMilliseconds(1659465600000).toString(), ), IndexerPnlTicksResponseObject( - id = "2", equity = "10000.0", totalPnl = "0.0", netTransfers = "0.0", @@ -276,14 +274,12 @@ class VaultTests { ticker = "BTC-USD", historicalPnl = arrayOf( IndexerPnlTicksResponseObject( - id = "1", equity = "10500.0", totalPnl = "500.0", netTransfers = "0.0", createdAt = Instant.fromEpochMilliseconds(1659465600000).toString(), ), IndexerPnlTicksResponseObject( - id = "2", equity = "10000.0", totalPnl = "0.0", netTransfers = "0.0", diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt b/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt index da1e2420d..b6205f485 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt @@ -11,7 +11,6 @@ import exchange.dydx.abacus.state.helper.NetworkParam import exchange.dydx.abacus.state.machine.TradingStateMachine import exchange.dydx.abacus.state.machine.account import exchange.dydx.abacus.state.machine.candles -import exchange.dydx.abacus.state.machine.fills import exchange.dydx.abacus.state.machine.historicalFundings import exchange.dydx.abacus.state.machine.historicalPnl import exchange.dydx.abacus.state.machine.onChainEquityTiers @@ -25,6 +24,7 @@ import exchange.dydx.abacus.state.machine.receivedBatchedMarketsChanges import exchange.dydx.abacus.state.machine.receivedBatchedTradesChanges import exchange.dydx.abacus.state.machine.receivedCandles import exchange.dydx.abacus.state.machine.receivedCandlesChanges +import exchange.dydx.abacus.state.machine.receivedFills import exchange.dydx.abacus.state.machine.receivedMarkets import exchange.dydx.abacus.state.machine.receivedMarketsChanges import exchange.dydx.abacus.state.machine.receivedOrderbook @@ -32,8 +32,8 @@ import exchange.dydx.abacus.state.machine.receivedSubaccountSubscribed import exchange.dydx.abacus.state.machine.receivedSubaccountsChanges import exchange.dydx.abacus.state.machine.receivedTrades import exchange.dydx.abacus.state.machine.receivedTradesChanges +import exchange.dydx.abacus.state.machine.receivedTransfers import exchange.dydx.abacus.state.machine.sparklines -import exchange.dydx.abacus.state.machine.transfers import exchange.dydx.abacus.state.manager.BlockAndTime import exchange.dydx.abacus.tests.payloads.AbacusMockData import exchange.dydx.abacus.utils.ServerTime @@ -640,3 +640,21 @@ fun TradingStateMachine.rest( val errors = if (error != null) iListOf(error) else null return StateResponse(state, changes, errors) } + +private fun TradingStateMachine.transfers(payload: String, subaccountNumber: Int): StateChanges { + val json = parser.decodeJsonObject(payload) + return if (json != null) { + receivedTransfers(json, subaccountNumber) + } else { + StateChanges.noChange + } +} + +private fun TradingStateMachine.fills(payload: String, subaccountNumber: Int): StateChanges { + val json = parser.decodeJsonObject(payload) + return if (json != null) { + receivedFills(json, subaccountNumber) + } else { + StateChanges.noChange + } +} \ No newline at end of file diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/tests/payloads/VaultMocks.kt b/src/commonTest/kotlin/exchange.dydx.abacus/tests/payloads/VaultMocks.kt index 115241fca..1703857de 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/tests/payloads/VaultMocks.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/tests/payloads/VaultMocks.kt @@ -42,14 +42,12 @@ internal class VaultMocks { ticker = "BTC-USD", historicalPnl = arrayOf( IndexerPnlTicksResponseObject( - id = "1", equity = "10500.0", totalPnl = "500.0", netTransfers = "0.0", createdAt = now.minus(1.hours).toString(), ), IndexerPnlTicksResponseObject( - id = "2", equity = "10000.0", totalPnl = "0.0", netTransfers = "0.0", From c6494fb6ff5c656b4d8872e55ef169158eb1c26a Mon Sep 17 00:00:00 2001 From: Rui Date: Tue, 17 Jun 2025 00:09:38 +0800 Subject: [PATCH 2/7] Funding payments --- .../output/account/FundingPayment.kt | 16 +++++++ .../processor/wallet/WalletProcessor.kt | 14 +++++++ .../wallet/account/AccountProcessor.kt | 14 ++++++- .../wallet/account/FundingPaymentProcessor.kt | 42 +++++++++++++++++++ .../account/FundingPaymentsProcessor.kt | 35 ++++++++++++++++ .../wallet/account/SubaccountProcessor.kt | 16 +++++++ .../state/InternalState.kt | 3 ++ .../TradingStateMachine+FundingPayments.kt | 21 ++++++++++ .../manager/configs/V4StateManagerConfigs.kt | 2 + .../state/supervisor/SubaccountSupervisor.kt | 28 +++++++++++-- .../TradingStateMachine+TestUtils.kt | 2 +- 11 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 src/commonMain/kotlin/exchange.dydx.abacus/output/account/FundingPayment.kt create mode 100644 src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt create mode 100644 src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt create mode 100644 src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+FundingPayments.kt diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/output/account/FundingPayment.kt b/src/commonMain/kotlin/exchange.dydx.abacus/output/account/FundingPayment.kt new file mode 100644 index 000000000..6149c8905 --- /dev/null +++ b/src/commonMain/kotlin/exchange.dydx.abacus/output/account/FundingPayment.kt @@ -0,0 +1,16 @@ +package exchange.dydx.abacus.output.account + +import kollections.JsExport +import kotlinx.serialization.Serializable + +@JsExport +@Serializable +data class FundingPayment( + val createdAtInMilliseconds: Double, + val ticker: String, + val oraclePrice: Double, + val size: Double, + val side: PositionSide, + val rate: Double, + val payment: Double, +) diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/WalletProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/WalletProcessor.kt index fba86c886..0f2b23f0a 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/WalletProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/WalletProcessor.kt @@ -11,6 +11,7 @@ import exchange.dydx.abacus.state.manager.BlockAndTime import exchange.dydx.abacus.state.manager.HistoricalTradingRewardsPeriod import exchange.dydx.abacus.utils.mutable import exchange.dydx.abacus.utils.safeSet +import indexer.codegen.IndexerFundingPaymentResponseObject import indexer.codegen.IndexerHistoricalTradingRewardAggregation import indexer.codegen.IndexerPnlTicksResponseObject import indexer.codegen.IndexerTransferResponseObject @@ -181,6 +182,19 @@ internal class WalletProcessor( return existing } + internal fun processFundingPayments( + existing: InternalWalletState, + payload: List?, + subaccountNumber: Int, + ): InternalWalletState { + existing.account = v4accountProcessor.processFundingPayments( + existing = existing.account, + payload = payload, + subaccountNumber = subaccountNumber, + ) + return existing + } + internal fun processFills( existing: InternalWalletState, payload: List?, diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/AccountProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/AccountProcessor.kt index 28829731f..a2c7d36f0 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/AccountProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/AccountProcessor.kt @@ -15,6 +15,7 @@ import exchange.dydx.abacus.state.InternalSubaccountState import exchange.dydx.abacus.state.manager.BlockAndTime import exchange.dydx.abacus.state.manager.HistoricalTradingRewardsPeriod import exchange.dydx.abacus.utils.safeSet +import indexer.codegen.IndexerFundingPaymentResponseObject import indexer.codegen.IndexerHistoricalBlockTradingReward import indexer.codegen.IndexerHistoricalTradingRewardAggregation import indexer.codegen.IndexerPnlTicksResponseObject @@ -218,6 +219,17 @@ internal class V4AccountProcessor( return existing } + internal fun processFundingPayments( + existing: InternalAccountState, + payload: List?, + subaccountNumber: Int, + ): InternalAccountState { + val subaccount = existing.subaccounts[subaccountNumber] ?: InternalSubaccountState(subaccountNumber = subaccountNumber) + val newSubaccount = subaccountsProcessor.processFundingPayments(subaccount, payload) + existing.subaccounts[subaccountNumber] = newSubaccount + return existing + } + internal fun processFills( existing: InternalAccountState, payload: List?, @@ -229,7 +241,7 @@ internal class V4AccountProcessor( return existing } - fun processTransfers( + internal fun processTransfers( existing: InternalAccountState, payload: List?, subaccountNumber: Int, diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt new file mode 100644 index 000000000..82b71df15 --- /dev/null +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt @@ -0,0 +1,42 @@ +package exchange.dydx.abacus.processor.wallet.account + +import exchange.dydx.abacus.output.account.FundingPayment +import exchange.dydx.abacus.output.account.PositionSide +import exchange.dydx.abacus.processor.base.BaseProcessor +import exchange.dydx.abacus.protocols.ParserProtocol +import indexer.codegen.IndexerFundingPaymentResponseObject + +internal interface FundingPaymentProcessorProtocol { + fun process( + existing: FundingPayment?, + payload: IndexerFundingPaymentResponseObject, + ): FundingPayment? +} + +internal class FundingPaymentProcessor( + parser: ParserProtocol +) : BaseProcessor(parser), FundingPaymentProcessorProtocol { + + override fun process( + existing: FundingPayment?, + payload: IndexerFundingPaymentResponseObject + ): FundingPayment? { + val createdAt = parser.asDatetime(payload.createdAt) ?: return null + val ticker = parser.asString(payload.ticker) ?: return null + val oraclePrice = parser.asDouble(payload.oraclePrice) ?: return null + val size = parser.asDouble(payload.size) ?: return null + val side = PositionSide.invoke(payload.side) ?: return null + val rate = parser.asDouble(payload.rate) ?: return null + val payment = parser.asDouble(payload.payment) ?: return null + + return FundingPayment( + createdAtInMilliseconds = createdAt.toEpochMilliseconds().toDouble(), + ticker = ticker, + oraclePrice = oraclePrice, + size = size, + side = side, + rate = rate, + payment = payment, + ) + } +} diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt new file mode 100644 index 000000000..a3327b58e --- /dev/null +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt @@ -0,0 +1,35 @@ +package exchange.dydx.abacus.processor.wallet.account + +import exchange.dydx.abacus.output.account.FundingPayment +import exchange.dydx.abacus.processor.base.BaseProcessor +import exchange.dydx.abacus.protocols.ParserProtocol +import indexer.codegen.IndexerFundingPaymentResponseObject +import kotlinx.datetime.Instant + +internal class FundingPaymentsProcessor( + parser: ParserProtocol, + private val paymentProcessor: FundingPaymentProcessor = FundingPaymentProcessor(parser = parser) +) : BaseProcessor(parser) { + fun process( + existing: List?, + payload: List, + ): List? { + val new = payload.reversed().mapNotNull { eachPayload -> + paymentProcessor.process( + existing = null, + payload = eachPayload, + ) + } + return merge( + parser = parser, + existing = existing, + incoming = new, + timeField = { item -> + item?.createdAtInMilliseconds?.toLong()?.let { + Instant.fromEpochMilliseconds(it) + } + }, + ascending = true, + ) + } +} diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/SubaccountProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/SubaccountProcessor.kt index abbcae3bf..a6fd2f8d7 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/SubaccountProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/SubaccountProcessor.kt @@ -11,6 +11,7 @@ import exchange.dydx.abacus.state.InternalSubaccountCalculated import exchange.dydx.abacus.state.InternalSubaccountState import exchange.dydx.abacus.state.manager.BlockAndTime import indexer.codegen.IndexerAssetPositionResponseObject +import indexer.codegen.IndexerFundingPaymentResponseObject import indexer.codegen.IndexerPerpetualPositionResponseObject import indexer.codegen.IndexerPerpetualPositionStatus import indexer.codegen.IndexerPnlTicksResponseObject @@ -30,6 +31,7 @@ internal open class SubaccountProcessor( private val fillsProcessor = FillsProcessor(parser, localizer) private val transfersProcessor = TransfersProcessor(parser, localizer) private val historicalPNLsProcessor = HistoricalPNLsProcessor(parser) + private val fundingPaymentProcessor = FundingPaymentsProcessor(parser) private val subaccountCalculator = SubaccountCalculator(parser) internal fun processSubscribed( @@ -258,6 +260,20 @@ internal open class SubaccountProcessor( return existing } + internal fun processFundingPayments( + existing: InternalSubaccountState, + payload: List?, + ): InternalSubaccountState { + val newFundingPayments = fundingPaymentProcessor.process( + existing = existing.fundingPayments, + payload = payload ?: emptyList(), + ) + if (existing.fundingPayments != newFundingPayments) { + existing.fundingPayments = newFundingPayments + } + return existing + } + internal fun processFills( existing: InternalSubaccountState, payload: List?, diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/InternalState.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/InternalState.kt index 37203090f..47917c42b 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/InternalState.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/InternalState.kt @@ -15,6 +15,7 @@ import exchange.dydx.abacus.output.MarketOrderbook import exchange.dydx.abacus.output.MarketTrade import exchange.dydx.abacus.output.PerpetualMarket import exchange.dydx.abacus.output.WithdrawalGating +import exchange.dydx.abacus.output.account.FundingPayment import exchange.dydx.abacus.output.account.PositionSide import exchange.dydx.abacus.output.account.StakingRewards import exchange.dydx.abacus.output.account.SubaccountFill @@ -316,6 +317,7 @@ internal data class InternalSubaccountState( var orders: List? = null, var transfers: List? = null, var historicalPNLs: List? = null, + var fundingPayments: List? = null, var positions: Map? = null, var assetPositions: Map? = null, var subaccountNumber: Int, @@ -341,6 +343,7 @@ internal data class InternalSubaccountState( orders = orders?.map { it.copy() }, transfers = transfers?.map { it.copy() }, historicalPNLs = historicalPNLs?.map { it.copy() }, + fundingPayments = fundingPayments?.map { it.copy() }, positions = positions?.map { it.key to it.value.copy() }?.toMap(), assetPositions = assetPositions?.map { it.key to it.value.copy() }?.toMap(), subaccountNumber = subaccountNumber, diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+FundingPayments.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+FundingPayments.kt new file mode 100644 index 000000000..4c0fde0dc --- /dev/null +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine+FundingPayments.kt @@ -0,0 +1,21 @@ +package exchange.dydx.abacus.state.machine + +import exchange.dydx.abacus.protocols.asTypedObject +import exchange.dydx.abacus.state.Changes +import exchange.dydx.abacus.state.StateChanges +import indexer.codegen.IndexerFundingPaymentResponse +import kollections.iListOf + +internal fun TradingStateMachine.fundingPayments(payload: String, subaccountNumber: Int): StateChanges { + val response = parser.asTypedObject(payload) + if (response != null && response.fundingPayments.isNullOrEmpty().not()) { + walletProcessor.processFundingPayments( + existing = internalState.wallet, + payload = response.fundingPayments?.toList(), + subaccountNumber = subaccountNumber, + ) + return StateChanges(iListOf(Changes.fundingPayments), null, iListOf(subaccountNumber)) + } else { + return StateChanges(iListOf()) + } +} diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/configs/V4StateManagerConfigs.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/configs/V4StateManagerConfigs.kt index b477c6220..330776ec7 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/configs/V4StateManagerConfigs.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/configs/V4StateManagerConfigs.kt @@ -40,6 +40,8 @@ class V4StateManagerConfigs( "fills":"/v4/fills", "historical-pnl":"/v4/historical-pnl", "parent-historical-pnl":"/v4/historical-pnl/parentSubaccountNumber", + "funding-payment": "/v4/fundingPayments", + "parent-funding-payment": "/v4/fundingPayments/parentSubaccount", "transfers":"/v4/transfers", "historicalTradingRewardAggregations":"/v4/historicalTradingRewardAggregations", "parent-fills":"/v4/fills/parentSubaccountNumber", diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/supervisor/SubaccountSupervisor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/supervisor/SubaccountSupervisor.kt index b1360ebb0..a771ca300 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/supervisor/SubaccountSupervisor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/supervisor/SubaccountSupervisor.kt @@ -18,6 +18,7 @@ import exchange.dydx.abacus.state.machine.TradingStateMachine import exchange.dydx.abacus.state.machine.TriggerOrdersInputField import exchange.dydx.abacus.state.machine.adjustIsolatedMargin import exchange.dydx.abacus.state.machine.closePosition +import exchange.dydx.abacus.state.machine.fundingPayments import exchange.dydx.abacus.state.machine.historicalPnl import exchange.dydx.abacus.state.machine.receivedBatchSubaccountsChanges import exchange.dydx.abacus.state.machine.receivedFills @@ -39,6 +40,7 @@ import exchange.dydx.abacus.state.manager.HumanReadableSubaccountTransferPayload import exchange.dydx.abacus.state.manager.HumanReadableTriggerOrdersPayload import exchange.dydx.abacus.state.manager.HumanReadableWithdrawPayload import exchange.dydx.abacus.state.manager.TransactionQueue +import exchange.dydx.abacus.state.manager.configs.V4StateManagerConfigs.Companion.configs import exchange.dydx.abacus.state.manager.notification.NotificationsProvider import exchange.dydx.abacus.utils.AnalyticsUtils import exchange.dydx.abacus.utils.IList @@ -139,6 +141,9 @@ internal class SubaccountSupervisor( if (configs.retrieveHistoricalPnls) { retrieveHistoricalPnls() } + if (configs.retrieveFundingPayments) { + retrieveFundingPayments() + } } } @@ -194,9 +199,9 @@ internal class SubaccountSupervisor( if (url != null) { helper.get(url, params, null, callback = { _, response, httpCode, _ -> if (helper.success(httpCode) && response != null) { - val tranfers = helper.parser.decodeJsonObject(response) - if (tranfers != null && tranfers.size != 0) { - update(stateMachine.receivedTransfers(tranfers, subaccountNumber), oldState) + val transfers = helper.parser.decodeJsonObject(response) + if (transfers != null && transfers.size != 0) { + update(stateMachine.receivedTransfers(transfers, subaccountNumber), oldState) } } }) @@ -249,6 +254,20 @@ internal class SubaccountSupervisor( } } + internal fun retrieveFundingPayments() { + val oldState = stateMachine.state + val url = + helper.configs.privateApiUrl(if (configs.useParentSubaccount) "parent-funding-payment" else "funding-payment") + ?: return + val params = + if (configs.useParentSubaccount) parentSubaccountParams() else subaccountParams() + helper.get(url, params, null, callback = { _, response, httpCode, _ -> + if (helper.success(httpCode) && response != null) { + update(stateMachine.fundingPayments(response, subaccountNumber), oldState) + } + }) + } + @Throws(Exception::class) private fun subaccountChannelSubscription( parent: Boolean, @@ -624,6 +643,9 @@ internal class SubaccountSupervisor( if (configs.retrieveHistoricalPnls) { retrieveHistoricalPnls() } + if (configs.retrieveFundingPayments) { + retrieveFundingPayments() + } } if (socketConnected) { if (configs.subscribeToSubaccount) { diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt b/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt index b6205f485..26c4ad55b 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt @@ -657,4 +657,4 @@ private fun TradingStateMachine.fills(payload: String, subaccountNumber: Int): S } else { StateChanges.noChange } -} \ No newline at end of file +} From bb2e7c7b3acb0e31f2f10ac8f3a3a0e15dce2836 Mon Sep 17 00:00:00 2001 From: Rui Date: Tue, 17 Jun 2025 06:30:42 +0800 Subject: [PATCH 3/7] WIP --- .../output/account/FundingPayment.kt | 16 ----- .../account/SubaccountFundingPayment.kt | 71 ++++--------------- .../wallet/account/FundingPaymentProcessor.kt | 24 +++---- .../account/FundingPaymentsProcessor.kt | 10 +-- .../state/InternalState.kt | 4 +- .../state/machine/TradingStateMachine.kt | 9 +-- 6 files changed, 36 insertions(+), 98 deletions(-) delete mode 100644 src/commonMain/kotlin/exchange.dydx.abacus/output/account/FundingPayment.kt diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/output/account/FundingPayment.kt b/src/commonMain/kotlin/exchange.dydx.abacus/output/account/FundingPayment.kt deleted file mode 100644 index 6149c8905..000000000 --- a/src/commonMain/kotlin/exchange.dydx.abacus/output/account/FundingPayment.kt +++ /dev/null @@ -1,16 +0,0 @@ -package exchange.dydx.abacus.output.account - -import kollections.JsExport -import kotlinx.serialization.Serializable - -@JsExport -@Serializable -data class FundingPayment( - val createdAtInMilliseconds: Double, - val ticker: String, - val oraclePrice: Double, - val size: Double, - val side: PositionSide, - val rate: Double, - val payment: Double, -) diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/output/account/SubaccountFundingPayment.kt b/src/commonMain/kotlin/exchange.dydx.abacus/output/account/SubaccountFundingPayment.kt index 6b9f23ba1..28a379908 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/output/account/SubaccountFundingPayment.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/output/account/SubaccountFundingPayment.kt @@ -1,8 +1,6 @@ package exchange.dydx.abacus.output.account -import exchange.dydx.abacus.protocols.ParserProtocol import exchange.dydx.abacus.utils.IList -import exchange.dydx.abacus.utils.Logger import exchange.dydx.abacus.utils.ParsingHelper import kollections.JsExport import kollections.toIList @@ -17,66 +15,21 @@ data class SubaccountFundingPayment( val positionSize: Double, val price: Double?, val effectiveAtMilliSeconds: Double, + val side: PositionSide, ) { companion object { - internal fun create( - existing: SubaccountFundingPayment?, - parser: ParserProtocol, - data: Map<*, *>?, - ): SubaccountFundingPayment? { - Logger.d { "creating Account Funding Payment\n" } - - data?.let { - val marketId = parser.asString(data["marketId"]) - val payment = parser.asDouble(data["payment"]) - val rate = parser.asDouble(data["rate"]) - val positionSize = parser.asDouble(data["positionSize"]) - val price = parser.asDouble(data["price"]) - val effectiveAtMilliSeconds = - parser.asDatetime(data["effectiveAt"])?.toEpochMilliseconds()?.toDouble() - if (marketId != null && payment != null && rate != null && positionSize != null && effectiveAtMilliSeconds != null) { - return if (existing?.marketId != marketId || - existing.payment != payment || - existing.rate != rate || - existing.positionSize != positionSize || - existing.price != price || - existing.effectiveAtMilliSeconds != effectiveAtMilliSeconds - ) { - SubaccountFundingPayment( - marketId, - payment, - rate, - positionSize, - price, - effectiveAtMilliSeconds, - ) - } else { - existing - } - } - } - Logger.d { "Account Funding Payment not valid" } - return null - } - - fun create( + internal fun merge( existing: IList?, - parser: ParserProtocol, - data: List>?, - ): IList? { - return ParsingHelper.merge(parser, existing, data, { obj, itemData -> - val time1 = (obj as SubaccountFundingPayment).effectiveAtMilliSeconds - val time2 = - parser.asDatetime(itemData["effectiveAt"])?.toEpochMilliseconds() - ?.toDouble() - ParsingHelper.compare(time1, time2 ?: 0.0, true) - }, { _, obj, itemData -> - obj ?: SubaccountFundingPayment.create( - null, - parser, - parser.asMap(itemData), - ) - })?.toIList() + new: IList?, + ): IList { + return ParsingHelper.merge( + existing = existing, + new = new, + comparison = { obj, newItem -> + ParsingHelper.compare(obj.effectiveAtMilliSeconds, newItem.effectiveAtMilliSeconds, true) + }, + syncItems = true, + ).toIList() } } } diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt index 82b71df15..99838de28 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt @@ -1,16 +1,16 @@ package exchange.dydx.abacus.processor.wallet.account -import exchange.dydx.abacus.output.account.FundingPayment import exchange.dydx.abacus.output.account.PositionSide +import exchange.dydx.abacus.output.account.SubaccountFundingPayment import exchange.dydx.abacus.processor.base.BaseProcessor import exchange.dydx.abacus.protocols.ParserProtocol import indexer.codegen.IndexerFundingPaymentResponseObject internal interface FundingPaymentProcessorProtocol { fun process( - existing: FundingPayment?, + existing: SubaccountFundingPayment?, payload: IndexerFundingPaymentResponseObject, - ): FundingPayment? + ): SubaccountFundingPayment? } internal class FundingPaymentProcessor( @@ -18,9 +18,9 @@ internal class FundingPaymentProcessor( ) : BaseProcessor(parser), FundingPaymentProcessorProtocol { override fun process( - existing: FundingPayment?, + existing: SubaccountFundingPayment?, payload: IndexerFundingPaymentResponseObject - ): FundingPayment? { + ): SubaccountFundingPayment? { val createdAt = parser.asDatetime(payload.createdAt) ?: return null val ticker = parser.asString(payload.ticker) ?: return null val oraclePrice = parser.asDouble(payload.oraclePrice) ?: return null @@ -29,14 +29,14 @@ internal class FundingPaymentProcessor( val rate = parser.asDouble(payload.rate) ?: return null val payment = parser.asDouble(payload.payment) ?: return null - return FundingPayment( - createdAtInMilliseconds = createdAt.toEpochMilliseconds().toDouble(), - ticker = ticker, - oraclePrice = oraclePrice, - size = size, - side = side, - rate = rate, + return SubaccountFundingPayment( + marketId = ticker, payment = payment, + rate = rate, + positionSize = size, + price = oraclePrice, + effectiveAtMilliSeconds = createdAt.toEpochMilliseconds().toDouble(), + side = side, ) } } diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt index a3327b58e..426250b0c 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt @@ -1,6 +1,6 @@ package exchange.dydx.abacus.processor.wallet.account -import exchange.dydx.abacus.output.account.FundingPayment +import exchange.dydx.abacus.output.account.SubaccountFundingPayment import exchange.dydx.abacus.processor.base.BaseProcessor import exchange.dydx.abacus.protocols.ParserProtocol import indexer.codegen.IndexerFundingPaymentResponseObject @@ -11,10 +11,10 @@ internal class FundingPaymentsProcessor( private val paymentProcessor: FundingPaymentProcessor = FundingPaymentProcessor(parser = parser) ) : BaseProcessor(parser) { fun process( - existing: List?, + existing: List?, payload: List, - ): List? { - val new = payload.reversed().mapNotNull { eachPayload -> + ): List? { + val new = payload.mapNotNull { eachPayload -> paymentProcessor.process( existing = null, payload = eachPayload, @@ -25,7 +25,7 @@ internal class FundingPaymentsProcessor( existing = existing, incoming = new, timeField = { item -> - item?.createdAtInMilliseconds?.toLong()?.let { + item?.effectiveAtMilliSeconds?.toLong()?.let { Instant.fromEpochMilliseconds(it) } }, diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/InternalState.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/InternalState.kt index 47917c42b..2b3ef2da6 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/InternalState.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/InternalState.kt @@ -15,10 +15,10 @@ import exchange.dydx.abacus.output.MarketOrderbook import exchange.dydx.abacus.output.MarketTrade import exchange.dydx.abacus.output.PerpetualMarket import exchange.dydx.abacus.output.WithdrawalGating -import exchange.dydx.abacus.output.account.FundingPayment import exchange.dydx.abacus.output.account.PositionSide import exchange.dydx.abacus.output.account.StakingRewards import exchange.dydx.abacus.output.account.SubaccountFill +import exchange.dydx.abacus.output.account.SubaccountFundingPayment import exchange.dydx.abacus.output.account.SubaccountHistoricalPNL import exchange.dydx.abacus.output.account.SubaccountOrder import exchange.dydx.abacus.output.account.SubaccountPositionResources @@ -317,7 +317,7 @@ internal data class InternalSubaccountState( var orders: List? = null, var transfers: List? = null, var historicalPNLs: List? = null, - var fundingPayments: List? = null, + var fundingPayments: List? = null, var positions: Map? = null, var assetPositions: Map? = null, var subaccountNumber: Int, diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine.kt index b1b10e42f..080bb29b0 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/machine/TradingStateMachine.kt @@ -796,10 +796,11 @@ open class TradingStateMachine( if (changes.changes.contains(Changes.fundingPayments)) { val modifiedFundingPayments = fundingPayments?.toIMutableMap() ?: mutableMapOf() var subaccountFundingPayments = fundingPayments?.get(subaccountText) - subaccountFundingPayments = SubaccountFundingPayment.create( - subaccountFundingPayments, - parser, - subaccountFundingPayments(subaccountNumber) as? IList>, + val newPayments = + internalState.wallet.account.subaccounts[subaccountNumber]?.fundingPayments?.toIList() + subaccountFundingPayments = SubaccountFundingPayment.merge( + existing = subaccountFundingPayments, + new = newPayments, ) modifiedFundingPayments.typedSafeSet(subaccountText, subaccountFundingPayments) fundingPayments = modifiedFundingPayments From 852f5e4de75892af35c37050a511b81f6b7436bf Mon Sep 17 00:00:00 2001 From: Rui Date: Wed, 18 Jun 2025 01:12:46 +0800 Subject: [PATCH 4/7] Version bump --- build.gradle.kts | 2 +- v4_abacus.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 041b262a6..e656c3d8b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -53,7 +53,7 @@ allprojects { } group = "exchange.dydx.abacus" -version = "1.14.6" +version = "1.14.7" repositories { google() diff --git a/v4_abacus.podspec b/v4_abacus.podspec index a410f6940..48291d230 100644 --- a/v4_abacus.podspec +++ b/v4_abacus.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'v4_abacus' - spec.version = '1.14.6' + spec.version = '1.14.7' spec.homepage = 'https://github.com/dydxprotocol/v4-abacus' spec.source = { :http=> ''} spec.authors = '' From 48c09e0b0f157b6a60bee2b52aa1862d9d9171c3 Mon Sep 17 00:00:00 2001 From: Rui Date: Wed, 18 Jun 2025 01:28:31 +0800 Subject: [PATCH 5/7] Fix tests --- .../app/manager/v2/V4ForegroundCycleTests.kt | 4 ++++ .../kotlin/exchange.dydx.abacus/payload/BaseTests.kt | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/app/manager/v2/V4ForegroundCycleTests.kt b/src/commonTest/kotlin/exchange.dydx.abacus/app/manager/v2/V4ForegroundCycleTests.kt index 33a7d7839..d75ef6fc8 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/app/manager/v2/V4ForegroundCycleTests.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/app/manager/v2/V4ForegroundCycleTests.kt @@ -420,6 +420,7 @@ class V4ForegroundCycleTests : NetworkTests() { "https://indexer.v4staging.dydx.exchange/v4/fills?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/transfers?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/historical-pnl?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", + "https://indexer.v4staging.dydx.exchange/v4/fundingPayments?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/historicalTradingRewardAggregations/cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm?period=DAILY" ] """.trimIndent(), @@ -533,6 +534,7 @@ class V4ForegroundCycleTests : NetworkTests() { "https://indexer.v4staging.dydx.exchange/v4/transfers?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/historical-pnl?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/historical-pnl?createdOnOrAfter=2022-08-08T21:07:24.581Z&address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", + "https://indexer.v4staging.dydx.exchange/v4/fundingPayments?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/historicalTradingRewardAggregations/cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm?period=DAILY" ] """.trimIndent(), @@ -581,6 +583,7 @@ class V4ForegroundCycleTests : NetworkTests() { "https://indexer.v4staging.dydx.exchange/v4/fills?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/transfers?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/historical-pnl?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", + "https://indexer.v4staging.dydx.exchange/v4/fundingPayments?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/historicalTradingRewardAggregations/cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm?period=DAILY", "https://indexer.v4staging.dydx.exchange/v4/screen?address=cosmos1d67qczf2dz0n30qau2wg893fhpdeekmfu44p4f", "https://indexer.v4staging.dydx.exchange/v4/compliance/screen/cosmos1d67qczf2dz0n30qau2wg893fhpdeekmfu44p4f", @@ -667,6 +670,7 @@ class V4ForegroundCycleTests : NetworkTests() { "https://indexer.v4staging.dydx.exchange/v4/fills?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/transfers?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/historical-pnl?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", + "https://indexer.v4staging.dydx.exchange/v4/fundingPayments?address=cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm&subaccountNumber=0", "https://indexer.v4staging.dydx.exchange/v4/historicalTradingRewardAggregations/cosmos1fq8q55896ljfjj7v3x0qd0z3sr78wmes940uhm?period=DAILY" ] """.trimIndent(), diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/payload/BaseTests.kt b/src/commonTest/kotlin/exchange.dydx.abacus/payload/BaseTests.kt index 35ce1391a..5b2f1b7c3 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/payload/BaseTests.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/payload/BaseTests.kt @@ -1863,7 +1863,6 @@ open class BaseTests( ) } } else { - assertTrue { obj.isNullOrEmpty() } } } From dc2238e9223304abc9113075a6f0d78382dd85a5 Mon Sep 17 00:00:00 2001 From: Rui Date: Thu, 19 Jun 2025 02:15:16 +0800 Subject: [PATCH 6/7] var name --- docs/SubAccount/SubAccountFundingPayment.md | 4 ++-- .../output/account/SubaccountFundingPayment.kt | 4 ++-- .../processor/wallet/account/FundingPaymentProcessor.kt | 2 +- .../processor/wallet/account/FundingPaymentsProcessor.kt | 2 +- .../kotlin/exchange.dydx.abacus/payload/BaseTests.kt | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/SubAccount/SubAccountFundingPayment.md b/docs/SubAccount/SubAccountFundingPayment.md index 815c09aef..6268baee1 100644 --- a/docs/SubAccount/SubAccountFundingPayment.md +++ b/docs/SubAccount/SubAccountFundingPayment.md @@ -6,7 +6,7 @@ data class SubaccountFundingPayment(  val rate: Double,  val positionSize: Double,  val price: Double?, - val effectiveAtMilliSeconds: Double + val createdAtMilliseconds: Double ) ## marketId @@ -29,6 +29,6 @@ Position size at the moment of payment price -## effectiveAtMilliSeconds +## createdAtMilliseconds Timestamp of the funding payment \ No newline at end of file diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/output/account/SubaccountFundingPayment.kt b/src/commonMain/kotlin/exchange.dydx.abacus/output/account/SubaccountFundingPayment.kt index 28a379908..ed0e4f7ca 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/output/account/SubaccountFundingPayment.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/output/account/SubaccountFundingPayment.kt @@ -14,7 +14,7 @@ data class SubaccountFundingPayment( val rate: Double, val positionSize: Double, val price: Double?, - val effectiveAtMilliSeconds: Double, + val createdAtMilliseconds: Double, val side: PositionSide, ) { companion object { @@ -26,7 +26,7 @@ data class SubaccountFundingPayment( existing = existing, new = new, comparison = { obj, newItem -> - ParsingHelper.compare(obj.effectiveAtMilliSeconds, newItem.effectiveAtMilliSeconds, true) + ParsingHelper.compare(obj.createdAtMilliseconds, newItem.createdAtMilliseconds, true) }, syncItems = true, ).toIList() diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt index 99838de28..7e714f557 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentProcessor.kt @@ -35,7 +35,7 @@ internal class FundingPaymentProcessor( rate = rate, positionSize = size, price = oraclePrice, - effectiveAtMilliSeconds = createdAt.toEpochMilliseconds().toDouble(), + createdAtMilliseconds = createdAt.toEpochMilliseconds().toDouble(), side = side, ) } diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt index 426250b0c..b36480409 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/FundingPaymentsProcessor.kt @@ -25,7 +25,7 @@ internal class FundingPaymentsProcessor( existing = existing, incoming = new, timeField = { item -> - item?.effectiveAtMilliSeconds?.toLong()?.let { + item?.createdAtMilliseconds?.toLong()?.let { Instant.fromEpochMilliseconds(it) } }, diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/payload/BaseTests.kt b/src/commonTest/kotlin/exchange.dydx.abacus/payload/BaseTests.kt index 5b2f1b7c3..d14181e2f 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/payload/BaseTests.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/payload/BaseTests.kt @@ -1904,7 +1904,7 @@ open class BaseTests( ) assertEquals( parser.asDatetime(data["effectiveAt"])?.toEpochMilliseconds()?.toDouble(), - obj.effectiveAtMilliSeconds, + obj.createdAtMilliseconds, "$trace.effectiveAt", ) } else { From ab29af5ee7857aab2748d3f0e92478ed5fb8a8f4 Mon Sep 17 00:00:00 2001 From: Rui Date: Thu, 19 Jun 2025 02:17:24 +0800 Subject: [PATCH 7/7] Add isInstantDeposit to DepositInitialized --- .../exchange.dydx.abacus/functional/ClientAnalyticEvents.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/functional/ClientAnalyticEvents.kt b/src/commonMain/kotlin/exchange.dydx.abacus/functional/ClientAnalyticEvents.kt index 57900629e..2906fb466 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/functional/ClientAnalyticEvents.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/functional/ClientAnalyticEvents.kt @@ -149,7 +149,8 @@ class ClientTrackableEventType { class DepositInitiatedEvent( private val transferInput: TransferInput, - private val summary: TransferInputSummary? + private val summary: TransferInputSummary?, + private val isInstantDeposit: Boolean ) : ClientTrackableEvent { override val name: String get() = "DepositInitiated" override val customParameters: Map get() = mapOf( @@ -161,6 +162,7 @@ class ClientTrackableEventType { "estimatedAmountOut" to summary?.toAmountMin, "swapPriceImpactPercent" to summary?.aggregatePriceImpact, "estimatedRouteDurationSeconds" to summary?.estimatedRouteDurationSeconds, + "isInstantDeposit" to isInstantDeposit, ).filterValues { it != null } as Map }