Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ allprojects {
}

group = "exchange.dydx.abacus"
version = "1.14.6"
version = "1.14.7"

repositories {
google()
Expand Down
4 changes: 2 additions & 2 deletions docs/SubAccount/SubAccountFundingPayment.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ data class SubaccountFundingPayment(
 val rate: Double,
 val positionSize: Double,
 val price: Double?,
 val effectiveAtMilliSeconds: Double
 val createdAtMilliseconds: Double
)

## marketId
Expand All @@ -29,6 +29,6 @@ Position size at the moment of payment

price

## effectiveAtMilliSeconds
## createdAtMilliseconds

Timestamp of the funding payment
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, Any> get() = mapOf(
Expand All @@ -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<String, Any>
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -16,67 +14,22 @@ data class SubaccountFundingPayment(
val rate: Double,
val positionSize: Double,
val price: Double?,
val effectiveAtMilliSeconds: Double,
val createdAtMilliseconds: 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<SubaccountFundingPayment>?,
parser: ParserProtocol,
data: List<Map<String, Any>>?,
): IList<SubaccountFundingPayment>? {
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<SubaccountFundingPayment>?,
): IList<SubaccountFundingPayment> {
return ParsingHelper.merge(
existing = existing,
new = new,
comparison = { obj, newItem ->
ParsingHelper.compare(obj.createdAtMilliseconds, newItem.createdAtMilliseconds, true)
},
syncItems = true,
).toIList()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -181,6 +182,19 @@ internal class WalletProcessor(
return existing
}

internal fun processFundingPayments(
existing: InternalWalletState,
payload: List<IndexerFundingPaymentResponseObject>?,
subaccountNumber: Int,
): InternalWalletState {
existing.account = v4accountProcessor.processFundingPayments(
existing = existing.account,
payload = payload,
subaccountNumber = subaccountNumber,
)
return existing
}

internal fun processFills(
existing: InternalWalletState,
payload: List<IndexerCompositeFillObject>?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -218,6 +219,17 @@ internal class V4AccountProcessor(
return existing
}

internal fun processFundingPayments(
existing: InternalAccountState,
payload: List<IndexerFundingPaymentResponseObject>?,
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<IndexerCompositeFillObject>?,
Expand All @@ -229,7 +241,7 @@ internal class V4AccountProcessor(
return existing
}

fun processTransfers(
internal fun processTransfers(
existing: InternalAccountState,
payload: List<IndexerTransferResponseObject>?,
subaccountNumber: Int,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package exchange.dydx.abacus.processor.wallet.account

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: SubaccountFundingPayment?,
payload: IndexerFundingPaymentResponseObject,
): SubaccountFundingPayment?
}

internal class FundingPaymentProcessor(
parser: ParserProtocol
) : BaseProcessor(parser), FundingPaymentProcessorProtocol {

override fun process(
existing: SubaccountFundingPayment?,
payload: IndexerFundingPaymentResponseObject
): 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
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 SubaccountFundingPayment(
marketId = ticker,
payment = payment,
rate = rate,
positionSize = size,
price = oraclePrice,
createdAtMilliseconds = createdAt.toEpochMilliseconds().toDouble(),
side = side,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package exchange.dydx.abacus.processor.wallet.account

import exchange.dydx.abacus.output.account.SubaccountFundingPayment
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<SubaccountFundingPayment>?,
payload: List<IndexerFundingPaymentResponseObject>,
): List<SubaccountFundingPayment>? {
val new = payload.mapNotNull { eachPayload ->
paymentProcessor.process(
existing = null,
payload = eachPayload,
)
}
return merge(
parser = parser,
existing = existing,
incoming = new,
timeField = { item ->
item?.createdAtMilliseconds?.toLong()?.let {
Instant.fromEpochMilliseconds(it)
}
},
ascending = true,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -258,6 +260,20 @@ internal open class SubaccountProcessor(
return existing
}

internal fun processFundingPayments(
existing: InternalSubaccountState,
payload: List<IndexerFundingPaymentResponseObject>?,
): 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<IndexerCompositeFillObject>?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import exchange.dydx.abacus.output.WithdrawalGating
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
Expand Down Expand Up @@ -316,6 +317,7 @@ internal data class InternalSubaccountState(
var orders: List<SubaccountOrder>? = null,
var transfers: List<SubaccountTransfer>? = null,
var historicalPNLs: List<SubaccountHistoricalPNL>? = null,
var fundingPayments: List<SubaccountFundingPayment>? = null,
var positions: Map<String, InternalPerpetualPosition>? = null,
var assetPositions: Map<String, InternalAssetPositionState>? = null,
var subaccountNumber: Int,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<IndexerFundingPaymentResponse>(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<Changes>())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, Any>,
subaccountNumber: Int,
Expand All @@ -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<String, Any>,
subaccountNumber: Int,
Expand Down
Loading