Skip to content

Commit 07bafc4

Browse files
authored
Add funding payments processing (#816)
1 parent 722e9b8 commit 07bafc4

28 files changed

+305
-108
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ allprojects {
5353
}
5454

5555
group = "exchange.dydx.abacus"
56-
version = "1.14.6"
56+
version = "1.14.7"
5757

5858
repositories {
5959
google()

docs/SubAccount/SubAccountFundingPayment.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ data class SubaccountFundingPayment(
66
 val rate: Double,
77
 val positionSize: Double,
88
 val price: Double?,
9-
 val effectiveAtMilliSeconds: Double
9+
 val createdAtMilliseconds: Double
1010
)
1111

1212
## marketId
@@ -29,6 +29,6 @@ Position size at the moment of payment
2929

3030
price
3131

32-
## effectiveAtMilliSeconds
32+
## createdAtMilliseconds
3333

3434
Timestamp of the funding payment

src/commonMain/kotlin/exchange.dydx.abacus/functional/ClientAnalyticEvents.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ class ClientTrackableEventType {
149149

150150
class DepositInitiatedEvent(
151151
private val transferInput: TransferInput,
152-
private val summary: TransferInputSummary?
152+
private val summary: TransferInputSummary?,
153+
private val isInstantDeposit: Boolean
153154
) : ClientTrackableEvent {
154155
override val name: String get() = "DepositInitiated"
155156
override val customParameters: Map<String, Any> get() = mapOf(
@@ -161,6 +162,7 @@ class ClientTrackableEventType {
161162
"estimatedAmountOut" to summary?.toAmountMin,
162163
"swapPriceImpactPercent" to summary?.aggregatePriceImpact,
163164
"estimatedRouteDurationSeconds" to summary?.estimatedRouteDurationSeconds,
165+
"isInstantDeposit" to isInstantDeposit,
164166
).filterValues { it != null } as Map<String, Any>
165167
}
166168

Lines changed: 13 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package exchange.dydx.abacus.output.account
22

3-
import exchange.dydx.abacus.protocols.ParserProtocol
43
import exchange.dydx.abacus.utils.IList
5-
import exchange.dydx.abacus.utils.Logger
64
import exchange.dydx.abacus.utils.ParsingHelper
75
import kollections.JsExport
86
import kollections.toIList
@@ -16,67 +14,22 @@ data class SubaccountFundingPayment(
1614
val rate: Double,
1715
val positionSize: Double,
1816
val price: Double?,
19-
val effectiveAtMilliSeconds: Double,
17+
val createdAtMilliseconds: Double,
18+
val side: PositionSide,
2019
) {
2120
companion object {
22-
internal fun create(
23-
existing: SubaccountFundingPayment?,
24-
parser: ParserProtocol,
25-
data: Map<*, *>?,
26-
): SubaccountFundingPayment? {
27-
Logger.d { "creating Account Funding Payment\n" }
28-
29-
data?.let {
30-
val marketId = parser.asString(data["marketId"])
31-
val payment = parser.asDouble(data["payment"])
32-
val rate = parser.asDouble(data["rate"])
33-
val positionSize = parser.asDouble(data["positionSize"])
34-
val price = parser.asDouble(data["price"])
35-
val effectiveAtMilliSeconds =
36-
parser.asDatetime(data["effectiveAt"])?.toEpochMilliseconds()?.toDouble()
37-
if (marketId != null && payment != null && rate != null && positionSize != null && effectiveAtMilliSeconds != null) {
38-
return if (existing?.marketId != marketId ||
39-
existing.payment != payment ||
40-
existing.rate != rate ||
41-
existing.positionSize != positionSize ||
42-
existing.price != price ||
43-
existing.effectiveAtMilliSeconds != effectiveAtMilliSeconds
44-
) {
45-
SubaccountFundingPayment(
46-
marketId,
47-
payment,
48-
rate,
49-
positionSize,
50-
price,
51-
effectiveAtMilliSeconds,
52-
)
53-
} else {
54-
existing
55-
}
56-
}
57-
}
58-
Logger.d { "Account Funding Payment not valid" }
59-
return null
60-
}
61-
62-
fun create(
21+
internal fun merge(
6322
existing: IList<SubaccountFundingPayment>?,
64-
parser: ParserProtocol,
65-
data: List<Map<String, Any>>?,
66-
): IList<SubaccountFundingPayment>? {
67-
return ParsingHelper.merge(parser, existing, data, { obj, itemData ->
68-
val time1 = (obj as SubaccountFundingPayment).effectiveAtMilliSeconds
69-
val time2 =
70-
parser.asDatetime(itemData["effectiveAt"])?.toEpochMilliseconds()
71-
?.toDouble()
72-
ParsingHelper.compare(time1, time2 ?: 0.0, true)
73-
}, { _, obj, itemData ->
74-
obj ?: SubaccountFundingPayment.create(
75-
null,
76-
parser,
77-
parser.asMap(itemData),
78-
)
79-
})?.toIList()
23+
new: IList<SubaccountFundingPayment>?,
24+
): IList<SubaccountFundingPayment> {
25+
return ParsingHelper.merge(
26+
existing = existing,
27+
new = new,
28+
comparison = { obj, newItem ->
29+
ParsingHelper.compare(obj.createdAtMilliseconds, newItem.createdAtMilliseconds, true)
30+
},
31+
syncItems = true,
32+
).toIList()
8033
}
8134
}
8235
}

src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/WalletProcessor.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import exchange.dydx.abacus.state.manager.BlockAndTime
1111
import exchange.dydx.abacus.state.manager.HistoricalTradingRewardsPeriod
1212
import exchange.dydx.abacus.utils.mutable
1313
import exchange.dydx.abacus.utils.safeSet
14+
import indexer.codegen.IndexerFundingPaymentResponseObject
1415
import indexer.codegen.IndexerHistoricalTradingRewardAggregation
1516
import indexer.codegen.IndexerPnlTicksResponseObject
1617
import indexer.codegen.IndexerTransferResponseObject
@@ -181,6 +182,19 @@ internal class WalletProcessor(
181182
return existing
182183
}
183184

185+
internal fun processFundingPayments(
186+
existing: InternalWalletState,
187+
payload: List<IndexerFundingPaymentResponseObject>?,
188+
subaccountNumber: Int,
189+
): InternalWalletState {
190+
existing.account = v4accountProcessor.processFundingPayments(
191+
existing = existing.account,
192+
payload = payload,
193+
subaccountNumber = subaccountNumber,
194+
)
195+
return existing
196+
}
197+
184198
internal fun processFills(
185199
existing: InternalWalletState,
186200
payload: List<IndexerCompositeFillObject>?,

src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/AccountProcessor.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import exchange.dydx.abacus.state.InternalSubaccountState
1515
import exchange.dydx.abacus.state.manager.BlockAndTime
1616
import exchange.dydx.abacus.state.manager.HistoricalTradingRewardsPeriod
1717
import exchange.dydx.abacus.utils.safeSet
18+
import indexer.codegen.IndexerFundingPaymentResponseObject
1819
import indexer.codegen.IndexerHistoricalBlockTradingReward
1920
import indexer.codegen.IndexerHistoricalTradingRewardAggregation
2021
import indexer.codegen.IndexerPnlTicksResponseObject
@@ -218,6 +219,17 @@ internal class V4AccountProcessor(
218219
return existing
219220
}
220221

222+
internal fun processFundingPayments(
223+
existing: InternalAccountState,
224+
payload: List<IndexerFundingPaymentResponseObject>?,
225+
subaccountNumber: Int,
226+
): InternalAccountState {
227+
val subaccount = existing.subaccounts[subaccountNumber] ?: InternalSubaccountState(subaccountNumber = subaccountNumber)
228+
val newSubaccount = subaccountsProcessor.processFundingPayments(subaccount, payload)
229+
existing.subaccounts[subaccountNumber] = newSubaccount
230+
return existing
231+
}
232+
221233
internal fun processFills(
222234
existing: InternalAccountState,
223235
payload: List<IndexerCompositeFillObject>?,
@@ -229,7 +241,7 @@ internal class V4AccountProcessor(
229241
return existing
230242
}
231243

232-
fun processTransfers(
244+
internal fun processTransfers(
233245
existing: InternalAccountState,
234246
payload: List<IndexerTransferResponseObject>?,
235247
subaccountNumber: Int,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package exchange.dydx.abacus.processor.wallet.account
2+
3+
import exchange.dydx.abacus.output.account.PositionSide
4+
import exchange.dydx.abacus.output.account.SubaccountFundingPayment
5+
import exchange.dydx.abacus.processor.base.BaseProcessor
6+
import exchange.dydx.abacus.protocols.ParserProtocol
7+
import indexer.codegen.IndexerFundingPaymentResponseObject
8+
9+
internal interface FundingPaymentProcessorProtocol {
10+
fun process(
11+
existing: SubaccountFundingPayment?,
12+
payload: IndexerFundingPaymentResponseObject,
13+
): SubaccountFundingPayment?
14+
}
15+
16+
internal class FundingPaymentProcessor(
17+
parser: ParserProtocol
18+
) : BaseProcessor(parser), FundingPaymentProcessorProtocol {
19+
20+
override fun process(
21+
existing: SubaccountFundingPayment?,
22+
payload: IndexerFundingPaymentResponseObject
23+
): SubaccountFundingPayment? {
24+
val createdAt = parser.asDatetime(payload.createdAt) ?: return null
25+
val ticker = parser.asString(payload.ticker) ?: return null
26+
val oraclePrice = parser.asDouble(payload.oraclePrice) ?: return null
27+
val size = parser.asDouble(payload.size) ?: return null
28+
val side = PositionSide.invoke(payload.side) ?: return null
29+
val rate = parser.asDouble(payload.rate) ?: return null
30+
val payment = parser.asDouble(payload.payment) ?: return null
31+
32+
return SubaccountFundingPayment(
33+
marketId = ticker,
34+
payment = payment,
35+
rate = rate,
36+
positionSize = size,
37+
price = oraclePrice,
38+
createdAtMilliseconds = createdAt.toEpochMilliseconds().toDouble(),
39+
side = side,
40+
)
41+
}
42+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package exchange.dydx.abacus.processor.wallet.account
2+
3+
import exchange.dydx.abacus.output.account.SubaccountFundingPayment
4+
import exchange.dydx.abacus.processor.base.BaseProcessor
5+
import exchange.dydx.abacus.protocols.ParserProtocol
6+
import indexer.codegen.IndexerFundingPaymentResponseObject
7+
import kotlinx.datetime.Instant
8+
9+
internal class FundingPaymentsProcessor(
10+
parser: ParserProtocol,
11+
private val paymentProcessor: FundingPaymentProcessor = FundingPaymentProcessor(parser = parser)
12+
) : BaseProcessor(parser) {
13+
fun process(
14+
existing: List<SubaccountFundingPayment>?,
15+
payload: List<IndexerFundingPaymentResponseObject>,
16+
): List<SubaccountFundingPayment>? {
17+
val new = payload.mapNotNull { eachPayload ->
18+
paymentProcessor.process(
19+
existing = null,
20+
payload = eachPayload,
21+
)
22+
}
23+
return merge(
24+
parser = parser,
25+
existing = existing,
26+
incoming = new,
27+
timeField = { item ->
28+
item?.createdAtMilliseconds?.toLong()?.let {
29+
Instant.fromEpochMilliseconds(it)
30+
}
31+
},
32+
ascending = true,
33+
)
34+
}
35+
}

src/commonMain/kotlin/exchange.dydx.abacus/processor/wallet/account/SubaccountProcessor.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import exchange.dydx.abacus.state.InternalSubaccountCalculated
1111
import exchange.dydx.abacus.state.InternalSubaccountState
1212
import exchange.dydx.abacus.state.manager.BlockAndTime
1313
import indexer.codegen.IndexerAssetPositionResponseObject
14+
import indexer.codegen.IndexerFundingPaymentResponseObject
1415
import indexer.codegen.IndexerPerpetualPositionResponseObject
1516
import indexer.codegen.IndexerPerpetualPositionStatus
1617
import indexer.codegen.IndexerPnlTicksResponseObject
@@ -30,6 +31,7 @@ internal open class SubaccountProcessor(
3031
private val fillsProcessor = FillsProcessor(parser, localizer)
3132
private val transfersProcessor = TransfersProcessor(parser, localizer)
3233
private val historicalPNLsProcessor = HistoricalPNLsProcessor(parser)
34+
private val fundingPaymentProcessor = FundingPaymentsProcessor(parser)
3335
private val subaccountCalculator = SubaccountCalculator(parser)
3436

3537
internal fun processSubscribed(
@@ -258,6 +260,20 @@ internal open class SubaccountProcessor(
258260
return existing
259261
}
260262

263+
internal fun processFundingPayments(
264+
existing: InternalSubaccountState,
265+
payload: List<IndexerFundingPaymentResponseObject>?,
266+
): InternalSubaccountState {
267+
val newFundingPayments = fundingPaymentProcessor.process(
268+
existing = existing.fundingPayments,
269+
payload = payload ?: emptyList(),
270+
)
271+
if (existing.fundingPayments != newFundingPayments) {
272+
existing.fundingPayments = newFundingPayments
273+
}
274+
return existing
275+
}
276+
261277
internal fun processFills(
262278
existing: InternalSubaccountState,
263279
payload: List<IndexerCompositeFillObject>?,

src/commonMain/kotlin/exchange.dydx.abacus/state/InternalState.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import exchange.dydx.abacus.output.WithdrawalGating
1818
import exchange.dydx.abacus.output.account.PositionSide
1919
import exchange.dydx.abacus.output.account.StakingRewards
2020
import exchange.dydx.abacus.output.account.SubaccountFill
21+
import exchange.dydx.abacus.output.account.SubaccountFundingPayment
2122
import exchange.dydx.abacus.output.account.SubaccountHistoricalPNL
2223
import exchange.dydx.abacus.output.account.SubaccountOrder
2324
import exchange.dydx.abacus.output.account.SubaccountPositionResources
@@ -316,6 +317,7 @@ internal data class InternalSubaccountState(
316317
var orders: List<SubaccountOrder>? = null,
317318
var transfers: List<SubaccountTransfer>? = null,
318319
var historicalPNLs: List<SubaccountHistoricalPNL>? = null,
320+
var fundingPayments: List<SubaccountFundingPayment>? = null,
319321
var positions: Map<String, InternalPerpetualPosition>? = null,
320322
var assetPositions: Map<String, InternalAssetPositionState>? = null,
321323
var subaccountNumber: Int,
@@ -341,6 +343,7 @@ internal data class InternalSubaccountState(
341343
orders = orders?.map { it.copy() },
342344
transfers = transfers?.map { it.copy() },
343345
historicalPNLs = historicalPNLs?.map { it.copy() },
346+
fundingPayments = fundingPayments?.map { it.copy() },
344347
positions = positions?.map { it.key to it.value.copy() }?.toMap(),
345348
assetPositions = assetPositions?.map { it.key to it.value.copy() }?.toMap(),
346349
subaccountNumber = subaccountNumber,

0 commit comments

Comments
 (0)