-
Notifications
You must be signed in to change notification settings - Fork 91
/
pending_updates.go
178 lines (151 loc) · 5.24 KB
/
pending_updates.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package types
import (
"math/big"
"sort"
"github.com/dydxprotocol/v4-chain/protocol/lib"
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"
)
// pendingUpdates is a utility struct used for storing the working updates to all Subaccounts.
type PendingUpdates struct {
subaccountAssetUpdates map[satypes.SubaccountId]map[uint32]*big.Int
subaccountPerpetualUpdates map[satypes.SubaccountId]map[uint32]*big.Int
subaccountFee map[satypes.SubaccountId]*big.Int
}
// newPendingUpdates returns a new `pendingUpdates`.
func NewPendingUpdates() *PendingUpdates {
return &PendingUpdates{
subaccountAssetUpdates: make(map[satypes.SubaccountId]map[uint32]*big.Int),
subaccountPerpetualUpdates: make(map[satypes.SubaccountId]map[uint32]*big.Int),
subaccountFee: make(map[satypes.SubaccountId]*big.Int),
}
}
// ConvertToUpdates converts a `pendingUpdates` struct to a slice of Subaccount Updates.
func (p *PendingUpdates) ConvertToUpdates() []satypes.Update {
// Build a slice of all subaccounts which were updated.
var allSubaccounts = make([]satypes.SubaccountId, 0, len(p.subaccountAssetUpdates))
for subaccountId := range p.subaccountAssetUpdates {
allSubaccounts = append(allSubaccounts, subaccountId)
}
// Sort the subaccounts for determinism.
sort.Sort(satypes.SortedSubaccountIds(allSubaccounts))
// Iterate over all subaccounts to convert `*PendingUpdates` to `[]satypes.Update` for use in the
// subaccounts module.
var updates = make([]satypes.Update, 0, len(allSubaccounts))
for _, subaccountId := range allSubaccounts {
// Create an empty slice to store the asset updates for this subaccount.
assetUpdates := make(
[]satypes.AssetUpdate,
0,
len(p.subaccountAssetUpdates[subaccountId]),
)
pendingAssetUpdates := p.subaccountAssetUpdates[subaccountId]
for assetId, bigQuantumsDelta := range pendingAssetUpdates {
assetUpdate := satypes.AssetUpdate{
AssetId: assetId,
BigQuantumsDelta: bigQuantumsDelta,
}
assetUpdates = append(assetUpdates, assetUpdate)
}
if _, exists := pendingAssetUpdates[lib.UsdcAssetId]; !exists {
pendingAssetUpdates[lib.UsdcAssetId] = new(big.Int)
}
// Subtract quote balance delta with total fees paid by subaccount.
pendingAssetUpdates[lib.UsdcAssetId].Sub(
pendingAssetUpdates[lib.UsdcAssetId],
p.subaccountFee[subaccountId],
)
// Panic if there is more than one asset updates since we only support
// USDC asset at the moment.
if len(assetUpdates) > 1 {
panic(ErrAssetUpdateNotImplemented)
}
// Create an empty slice to store the perpetual updates for this subaccount.
perpetualUpdates := make(
[]satypes.PerpetualUpdate,
0,
len(p.subaccountPerpetualUpdates[subaccountId]),
)
for perpetualId, bigQuantumsDelta := range p.subaccountPerpetualUpdates[subaccountId] {
perpetualUpdate := satypes.PerpetualUpdate{
PerpetualId: perpetualId,
BigQuantumsDelta: bigQuantumsDelta,
}
perpetualUpdates = append(perpetualUpdates, perpetualUpdate)
}
// Sort the perpetualIds in ascending order for determinism.
sort.Slice(perpetualUpdates, func(i, j int) bool {
return perpetualUpdates[i].PerpetualId < perpetualUpdates[j].PerpetualId
})
// Create the update.
update := satypes.Update{
AssetUpdates: assetUpdates,
PerpetualUpdates: perpetualUpdates,
SubaccountId: subaccountId,
}
updates = append(updates, update)
}
return updates
}
// AddPerpetualFill adds a new fill to the PendingUpdate object, by
// updating quoteBalanceDelta, perpetualUpdate and fees paid or received by a subaccount.
func (p *PendingUpdates) AddPerpetualFill(
subaccountId satypes.SubaccountId,
perpetualId uint32,
isBuy bool,
feePpm int32,
bigFillBaseQuantums *big.Int,
bigFillQuoteQuantums *big.Int,
) {
var quoteBalanceUpdate *big.Int
var subaccountPerpetualUpdates map[uint32]*big.Int
var perpetualUpdate *big.Int
subaccountAssetUpdates, exists := p.subaccountAssetUpdates[subaccountId]
if !exists {
subaccountAssetUpdates = make(map[uint32]*big.Int)
p.subaccountAssetUpdates[subaccountId] = subaccountAssetUpdates
}
quoteBalanceUpdate, exists = subaccountAssetUpdates[lib.UsdcAssetId]
if !exists {
quoteBalanceUpdate = big.NewInt(0)
subaccountAssetUpdates[lib.UsdcAssetId] = quoteBalanceUpdate
}
subaccountPerpetualUpdates, exists = p.subaccountPerpetualUpdates[subaccountId]
if !exists {
subaccountPerpetualUpdates = make(map[uint32]*big.Int)
p.subaccountPerpetualUpdates[subaccountId] = subaccountPerpetualUpdates
}
perpetualUpdate, exists = subaccountPerpetualUpdates[perpetualId]
if !exists {
perpetualUpdate = big.NewInt(0)
subaccountPerpetualUpdates[perpetualId] = perpetualUpdate
}
if isBuy {
quoteBalanceUpdate.Sub(
quoteBalanceUpdate,
bigFillQuoteQuantums,
)
perpetualUpdate.Add(
perpetualUpdate,
bigFillBaseQuantums,
)
} else {
quoteBalanceUpdate.Add(
quoteBalanceUpdate,
bigFillQuoteQuantums,
)
perpetualUpdate.Sub(
perpetualUpdate,
bigFillBaseQuantums,
)
}
totalFee, exists := p.subaccountFee[subaccountId]
if !exists {
totalFee = big.NewInt(0)
}
bigFeeQuoteQuantums := lib.BigIntMulSignedPpm(bigFillQuoteQuantums, feePpm)
totalFee.Add(
totalFee,
bigFeeQuoteQuantums,
)
p.subaccountFee[subaccountId] = totalFee
}