This repository has been archived by the owner on Jun 2, 2022. It is now read-only.
forked from LedgerHQ/ledger-live-common
-
Notifications
You must be signed in to change notification settings - Fork 0
/
account.ts
308 lines (308 loc) · 12.4 KB
/
account.ts
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
import type { BigNumber } from "bignumber.js";
import type { CryptoCurrency, TokenCurrency, Unit } from "./currencies";
import type { OperationRaw, Operation } from "./operation";
import type { DerivationMode } from "../derivation";
import type {
BitcoinResources,
BitcoinResourcesRaw,
} from "../families/bitcoin/types";
import type { TronResources, TronResourcesRaw } from "../families/tron/types";
import type {
CosmosResources,
CosmosResourcesRaw,
} from "../families/cosmos/types";
import type {
AlgorandResources,
AlgorandResourcesRaw,
} from "../families/algorand/types";
import type {
PolkadotResources,
PolkadotResourcesRaw,
} from "../families/polkadot/types";
import type {
TezosResources,
TezosResourcesRaw,
} from "../families/tezos/types";
import type {
ElrondResources,
ElrondResourcesRaw,
} from "../families/elrond/types";
import type {
CryptoOrgResources,
CryptoOrgResourcesRaw,
} from "../families/crypto_org/types";
import type {
BalanceHistory,
BalanceHistoryRaw,
PortfolioRange,
} from "./portfolio";
import type { SwapOperation, SwapOperationRaw } from "../exchange/swap/types";
import type { NFT, NFTRaw } from "./nft";
// This is the old cache and now DEPRECATED (pre v2 portfoli)
export type BalanceHistoryMap = Partial<Record<PortfolioRange, BalanceHistory>>;
export type BalanceHistoryRawMap = Record<PortfolioRange, BalanceHistoryRaw>;
export type GranularityId = "HOUR" | "DAY" | "WEEK";
// the cache is maintained for as many granularity as we need on Live.
// it's currently an in memory cache so there is no problem regarding the storage.
// in future, it could be saved and we can rethink how it's stored (independently of how it's in memory)
export type BalanceHistoryCache = Record<
GranularityId,
BalanceHistoryDataCache
>;
// the way BalanceHistoryDataCache works is:
// - a "cursor" date which is the "latestDate" representing the latest datapoint date. it's null if it never was loaded or if it's empty.
// - an array of balances. balances are stored in JSNumber even tho internally calculated with bignumbers because we want very good perf. it shouldn't impact imprecision (which happens when we accumulate values, not when presenting to user)
// there are as much value in that array as there are historical datapoint for a given account.
// each time an account will sync, it potentially update it by adding a datapoint and possibility updating the cursor in that case.
export type BalanceHistoryDataCache = {
latestDate: number | null | undefined;
balances: number[];
};
// A token belongs to an Account and share the parent account address
export type TokenAccount = {
type: "TokenAccount";
id: string;
// id of the parent account this token account belongs to
parentId: string;
token: TokenCurrency;
balance: BigNumber;
spendableBalance: BigNumber;
// in case of compound, this is the associated balance for the associated ctoken
compoundBalance?: BigNumber;
creationDate: Date;
operationsCount: number;
operations: Operation[];
pendingOperations: Operation[];
starred: boolean;
// DEPRECATED! it will be dropped when switching to Portfolio V2
balanceHistory?: BalanceHistoryMap;
// Cache of balance history that allows a performant portfolio calculation.
// currently there are no "raw" version of it because no need to at this stage.
// could be in future when pagination is needed.
balanceHistoryCache: BalanceHistoryCache;
// Swap operations linked to this account
swapHistory: SwapOperation[];
approvals?: Array<{
sender: string;
value: string;
}>;
};
// A child account belongs to an Account but has its own address
export type ChildAccount = {
type: "ChildAccount";
id: string;
name: string;
starred: boolean;
// id of the parent account this token account belongs to
parentId: string;
currency: CryptoCurrency;
address: string;
balance: BigNumber;
creationDate: Date;
operationsCount: number;
operations: Operation[];
pendingOperations: Operation[];
// DEPRECATED! it will be dropped when switching to Portfolio V2
balanceHistory?: BalanceHistoryMap;
// Cache of balance history that allows a performant portfolio calculation.
// currently there are no "raw" version of it because no need to at this stage.
// could be in future when pagination is needed.
balanceHistoryCache: BalanceHistoryCache;
// Swap operations linked to this account
swapHistory: SwapOperation[];
};
export type Address = {
address: string;
derivationPath: string;
};
export type Account = {
type: "Account";
// unique account identifier
id: string;
// a unique way to identify a seed the account was associated with
// it MUST be different between 2 seeds
// but it is not necessarily the same between 2 accounts (if possible – not always possible)
// in BTC like accounts, we use pubKey(purpose'/coinType')
// For other accounts that don't have sub derivation, we have used the account address
seedIdentifier: string;
// account xpub if available
xpub?: string;
// Identify the derivation used. it allows us to map this to a derivation scheme.
// example of values: segwit | unsplit | segwit_unsplit | mew | eth_mew (eg for etc accounts on eth)
// the special value of '' means it's bip44 with purpose 44.
derivationMode: DerivationMode;
// the iterated number to derive the account in a given derivationMode config
// in context of bip44, it would be the account field of bip44 ( m/purpose'/cointype'/account' )
index: number;
// next receive address. to be used to display to user.
// (deprecated - corresponds to freshAddresses[0].address)
freshAddress: string;
// The path linked to freshAddress. to be used to validate with the device if it corresponds to freshAddress.
// example: 44'/0'/0'/0/0
// (deprecated - corresponds to freshAddresses[0].derivationPath)
freshAddressPath: string;
// an array containing all fresh addresses and paths
// may be empty if no sync has occurred
freshAddresses: Address[];
// account name
name: string;
// starred
starred: boolean;
// says if the account essentially "exists". an account has been used in the past, but for some reason the blockchain finds it empty (no ops, no balance,..)
used: boolean;
// account balance in satoshi
balance: BigNumber;
// part of the balance that can effectively be spent
spendableBalance: BigNumber;
// date the account started "existing", essentially the date of the older tx received/done of this account
// It is equal to Date.now() for EMPTY accounts because empty account don't really "exists"
creationDate: Date;
// the last block height currently synchronized
blockHeight: number;
// ------------------------------------- Specific account fields
// currency of this account
currency: CryptoCurrency;
// user preferred unit to use. unit is coming from currency.units. You can assume currency.units.indexOf(unit) will work. (make sure to preserve reference)
unit: Unit;
// The total number of operations (operations[] can be partial)
operationsCount: number;
// lazy list of operations that exists on the blockchain.
operations: Operation[];
// pending operations that has been broadcasted but are not yet in operations
// this is for optimistic updates UI. the Operation objects are temporary and
// might not be the real one that will arrives on operations array.
// only Operation#id needs to be guaranteed the same.
// the array resulting of pendingOperations.concat(operations)
// is guaranteed to contains unique ops (by id) at any time and also is time DESC sorted.
pendingOperations: Operation[];
// used to know when the last sync happened
lastSyncDate: Date;
// A configuration for the endpoint to use. (usecase: Ripple node)
// FIXME drop and introduce a config{} object
endpointConfig?: string | null | undefined;
// An account can have sub accounts.
// A sub account can be either a token account or a child account in some blockchain.
// They are attached to the parent account in the related blockchain.
// CONVENTION:
// a SubAccount is living inside an Account but is not an entity on its own,
// therefore, there is no .parentAccount in it, which will means you will need to always have a tuple of (parentAccount, account)
// we will use the naming (parentAccount, account) everywhere because a sub account is not enough and you need the full context with this tuple.
// These are two valid examples:
// I'm inside a ZRX token account of Ethereum 1: { parentAccount: Ethereum 1, account: ZRX }
// I'm just inside the Ethereum 1: { account: Ethereum 1, parentAccount: undefined }
// "account" is the primary account that you use/select/view. It is a `AccountLike`.
// "parentAccount", if available, is the contextual account. It is a `?Account`.
subAccounts?: SubAccount[];
// balance history represented the balance evolution throughout time, used by chart.
// This is to be refreshed when necessary (typically in a sync)
// this is a map PER granularity to allow a fast feedback when user switch them
// DEPRECATED! it will be dropped when switching to Portfolio V2
balanceHistory?: BalanceHistoryMap;
// Cache of balance history that allows a performant portfolio calculation.
// currently there are no "raw" version of it because no need to at this stage.
// could be in future when pagination is needed.
balanceHistoryCache: BalanceHistoryCache;
// On some blockchain, an account can have resources (gained, delegated, ...)
bitcoinResources?: BitcoinResources;
tronResources?: TronResources;
cosmosResources?: CosmosResources;
algorandResources?: AlgorandResources;
polkadotResources?: PolkadotResources;
tezosResources?: TezosResources;
elrondResources?: ElrondResources;
cryptoOrgResources?: CryptoOrgResources;
// Swap operations linked to this account
swapHistory: SwapOperation[];
// Hash used to discard tx history on sync
syncHash?: string;
// Array of NFTs computed by diffing NFTOperations ordered from newest to oldest
nfts?: NFT[];
};
export type SubAccount = TokenAccount | ChildAccount;
export type AccountLike = Account | SubAccount;
// Damn it flow. can't you support covariance.
export type AccountLikeArray = // $FlowFixMe wtf mobile
| AccountLike[]
| TokenAccount[]
| ChildAccount[]
| Account[];
export type TokenAccountRaw = {
type: "TokenAccountRaw";
id: string;
starred?: boolean;
parentId: string;
tokenId: string;
creationDate?: string;
operationsCount?: number;
operations: OperationRaw[];
pendingOperations: OperationRaw[];
balance: string;
spendableBalance?: string;
compoundBalance?: string;
balanceHistory?: BalanceHistoryRawMap;
balanceHistoryCache?: BalanceHistoryCache;
swapHistory?: SwapOperationRaw[];
approvals?: Array<{
sender: string;
value: string;
}>;
};
export type ChildAccountRaw = {
type: "ChildAccountRaw";
id: string;
name: string;
starred?: boolean;
parentId: string;
currencyId: string;
address: string;
creationDate?: string;
operationsCount?: number;
operations: OperationRaw[];
pendingOperations: OperationRaw[];
balance: string;
balanceHistory?: BalanceHistoryRawMap;
balanceHistoryCache?: BalanceHistoryCache;
swapHistory?: SwapOperationRaw[];
};
export type AccountRaw = {
id: string;
seedIdentifier: string;
xpub?: string;
derivationMode: DerivationMode;
index: number;
freshAddress: string;
freshAddressPath: string;
freshAddresses: Address[];
name: string;
starred?: boolean;
used?: boolean;
balance: string;
spendableBalance?: string;
blockHeight: number;
creationDate?: string;
operationsCount?: number;
// this is optional for backward compat
// ------------------------------------- Specific raw fields
currencyId: string;
operations: OperationRaw[];
pendingOperations: OperationRaw[];
unitMagnitude: number;
lastSyncDate: string;
endpointConfig?: string | null | undefined;
subAccounts?: SubAccountRaw[];
balanceHistory?: BalanceHistoryRawMap;
balanceHistoryCache?: BalanceHistoryCache;
bitcoinResources?: BitcoinResourcesRaw;
tronResources?: TronResourcesRaw;
cosmosResources?: CosmosResourcesRaw;
algorandResources?: AlgorandResourcesRaw;
polkadotResources?: PolkadotResourcesRaw;
elrondResources?: ElrondResourcesRaw;
tezosResources?: TezosResourcesRaw;
cryptoOrgResources?: CryptoOrgResourcesRaw;
swapHistory?: SwapOperationRaw[];
syncHash?: string;
nfts?: NFTRaw[];
};
export type SubAccountRaw = TokenAccountRaw | ChildAccountRaw;
export type AccountRawLike = AccountRaw | SubAccountRaw;