hedge-web3 0.1.40 → 0.1.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,8 @@ import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js'
2
2
  import Decimal from 'decimal.js'
3
3
  import { DecimalFromU128 } from '../HedgeDecimal'
4
4
 
5
+ import * as borsh from '@project-serum/borsh'
6
+
5
7
  /**
6
8
  * A class that represents an on-chian vault.
7
9
  */
@@ -24,14 +26,17 @@ export class VaultAccount {
24
26
  /** The ordered number of when this vault was created. */
25
27
  vaultNumber: number
26
28
 
27
- debtProductSnapshotBytes: Decimal
29
+ /** Debt redistribution snapshop */
30
+ debtProductSnapshotBytes = new Decimal(0)
28
31
 
29
- collateralAccumulatorSnapshotBytes: Decimal
32
+ /** Collateral redistribution snapshop' */
33
+ collateralAccumulatorSnapshotBytes = new Decimal(0)
30
34
 
35
+ /** The vault type eg 'SOL-150' */
31
36
  collateralType: string
32
37
 
33
38
  /** Current State of the vautl ("Open", "Closed", "Liquidated") */
34
- vaultStatus: string
39
+ vaultStatus = ''
35
40
 
36
41
  /** The public key of the next vault to redeem. */
37
42
  nextVaultToRedeem: PublicKey
@@ -39,16 +44,22 @@ export class VaultAccount {
39
44
  constructor(vault: any, publicKey: PublicKey) {
40
45
  this.publicKey = publicKey
41
46
  this.vaultOwner = vault.vaultOwner
42
- this.vaultNumber = vault.vaultNumber.toNumber()
47
+ this.vaultNumber = vault.vaultNumber?.toNumber()
43
48
  this.pdaSalt = vault.pdaSalt
44
- this.deposited = vault.deposited.toNumber()
45
- this.denormalizedDebt = vault.denormalizedDebt.toNumber()
46
- this.debtProductSnapshotBytes = DecimalFromU128(vault.debtProductSnapshotBytes.toString())
47
- this.collateralAccumulatorSnapshotBytes = DecimalFromU128(vault.collateralAccumulatorSnapshotBytes.toString())
49
+ this.deposited = vault.deposited?.toNumber()
50
+ this.denormalizedDebt = vault.denormalizedDebt?.toNumber()
51
+ if (vault.debtProductSnapshotBytes) {
52
+ this.debtProductSnapshotBytes = DecimalFromU128(vault.debtProductSnapshotBytes.toString())
53
+ }
54
+ if (vault.collateralAccumulatorSnapshotBytes) {
55
+ this.collateralAccumulatorSnapshotBytes = DecimalFromU128(vault.collateralAccumulatorSnapshotBytes.toString())
56
+ }
48
57
  this.collateralType = vault.collateralType
49
58
  this.nextVaultToRedeem = vault.nextVaultToRedeem
50
59
 
51
- this.vaultStatus = Object.keys(vault.vaultStatus)[0]
60
+ if (vault.vaultStatus) {
61
+ this.vaultStatus = Object.keys(vault.vaultStatus)[0]
62
+ }
52
63
  }
53
64
 
54
65
  /**
@@ -119,7 +130,7 @@ export class VaultAccount {
119
130
  .div(this.debtProductSnapshotBytes)
120
131
  .mul(new Decimal(this.denormalizedDebt))
121
132
  .toNumber()
122
-
133
+
123
134
  const extraCollateralDeposited =
124
135
  this.denormalizedDebt * collateralAccumulatorCurrent.sub(this.collateralAccumulatorSnapshotBytes).toNumber()
125
136
  this.deposited += extraCollateralDeposited
@@ -143,8 +154,45 @@ export class VaultAccount {
143
154
  nextVault = this.nextVaultToRedeem.toString().substring(0, 6)
144
155
  }
145
156
 
146
- return `Vault(${this.vaultNumber}): ${this.publicKey
147
- .toString()
148
- .substring(0, 6)}. Debt: ${this.denormalizedDebt} Collat: ${this.deposited} Ratio: ${collateralRatio} NextVault: ${nextVault} ${arrow} `
157
+ return `Vault(${this.vaultNumber}): ${this.publicKey.toString().substring(0, 6)}. Debt: ${
158
+ this.denormalizedDebt
159
+ } Collat: ${this.deposited} Ratio: ${collateralRatio} NextVault: ${nextVault} ${arrow} `
160
+ }
161
+ /**
162
+ * Creates a VaultAccount from a slice of data
163
+ *
164
+ * It only contains
165
+ * - Denormalized Debt
166
+ * - Deposit
167
+ * - Vault Number
168
+ *
169
+ * This can be used to do off-chain sort with very little data.
170
+ *
171
+ * @returns a new VaultAccount
172
+ */
173
+ static FromMiniSlice(data: Buffer, pubkey: PublicKey) {
174
+ const props = [borsh.u64('vaultNumber'), borsh.u64('deposited'), borsh.u64('denormalizedDebt')]
175
+ const miniVaultLayout = borsh.struct(props, 'minVaultLayout')
176
+ const decodedData: any = miniVaultLayout.decode(data)
177
+
178
+ return new VaultAccount(decodedData, pubkey)
179
+ }
180
+
181
+ /**
182
+ * Encode a string for doing byte comparison on solana
183
+ *
184
+ * @returns Buffer of the encoded string
185
+ */
186
+ static getBufferForString(string: string) {
187
+ const stringLayout = borsh.struct([borsh.str('name')], 'justStringLayout')
188
+ let buffer = Buffer.alloc(50)
189
+
190
+ stringLayout.encode({ name: string }, buffer)
191
+
192
+ // Trim empty space at end of buffer
193
+ while (buffer.at(buffer.length - 1) == 0) {
194
+ buffer = buffer.slice(0, buffer.length - 1)
195
+ }
196
+ return buffer
149
197
  }
150
198
  }
@@ -3,6 +3,7 @@ import { IDL } from '../idl/vault'
3
3
 
4
4
  export function parseAnchorErrors (error: any): void {
5
5
  const idlErrors = parseIdlErrors(IDL)
6
+ console.log(error)
6
7
  const parsedError = ProgramError.parse(error, idlErrors)
7
8
  if (parsedError !== null) {
8
9
  throw parsedError
@@ -1,12 +1,16 @@
1
1
  import { Program, Provider } from '@project-serum/anchor'
2
2
  import { PublicKey, Signer } from '@solana/web3.js'
3
3
  import _ from 'underscore'
4
- import { getVaultSystemStatePublicKey, getVaultTypeOracleAccountPublicKey } from '../Constants'
4
+ import { getVaultSystemStatePublicKey, getVaultTypeOracleAccountPublicKey, HEDGE_PROGRAM_PUBLICKEY } from '../Constants'
5
5
 
6
6
  import { DecimalFromU128 } from '../HedgeDecimal'
7
7
  import { VaultAccount } from '../state/VaultAccount'
8
8
  import Decimal from 'decimal.js'
9
9
  import { Vault } from 'idl/vault'
10
+
11
+ import * as borsh from '@project-serum/borsh'
12
+ import base58 from 'bs58'
13
+
10
14
  export async function getLinkedListAccounts(
11
15
  program: Program<Vault>,
12
16
  provider: Provider,
@@ -18,6 +22,7 @@ export async function getLinkedListAccounts(
18
22
  liquidate: boolean,
19
23
  cachedVaults?: VaultAccount[]
20
24
  ): Promise<[PublicKey, PublicKey, PublicKey, VaultAccount[]]> {
25
+ console.log('Getting getLinkedListAccounts')
21
26
  const vaultTypeAccount = await program.account.vaultType.fetch(vaultTypeAccountPublicKey)
22
27
 
23
28
  // Default for null is the vault itself, so set them all to this vault
@@ -33,32 +38,37 @@ export async function getLinkedListAccounts(
33
38
  if (cachedVaults) {
34
39
  vaults = cachedVaults
35
40
  } else {
36
- let allVaults = cachedVaults
37
- ? cachedVaults
38
- : (await program.account.vault
39
- .all([
40
- // {
41
- // memcmp: { bytes: bs58.encode(inputCollateralType), offset: 8 + 32 + 8 },
42
- // },
43
- ])
44
- .catch((error) => {
45
- console.log('error', error)
46
- })) || []
47
-
48
- // Load them into our account objects
49
- vaults = allVaults.map((vault) => {
50
- return new VaultAccount(vault.account, vault.publicKey)
51
- })
41
+ // let allVaults = cachedVaults
42
+ // ? cachedVaults
43
+ // : (await program.account.vault
44
+ // .all([
45
+ // {
46
+ // memcmp: { bytes: vaultTypeAccount.collateralType, offset: 8 + 32 + 8 },
47
+ // },
48
+ // ])
49
+ // .catch((error) => {
50
+ // console.log('error', error)
51
+ // })) || []
52
+
53
+ // // Load them into our account objects
54
+ // vaults = allVaults.map((vault) => {
55
+ // return new VaultAccount(vault.account, vault.publicKey)
56
+ // })
57
+ vaults = await getMiniVaults(program, vaultTypeAccount.collateralType)
52
58
  }
53
59
 
54
- // Filter out the account that are not the same vault type
55
- vaults = _.filter(vaults, (vault) => {
56
- return vault.collateralType === vaultTypeAccount.collateralType
57
- })
60
+ console.log('Vault count found:', vaults.length)
61
+ console.log('First Vault', vaults[0])
58
62
 
59
63
  // Filter out the accounts that are not open
64
+ // TODO filter on vault status. Or we enable people to "close out" empty vaults
65
+ // vaults = _.filter(vaults, (vault) => {
66
+ // return vault.vaultStatus === 'open'
67
+ // })
68
+
69
+ // Remove any vaults with no debt or collateral
60
70
  vaults = _.filter(vaults, (vault) => {
61
- return vault.vaultStatus === 'open'
71
+ return vault.denormalizedDebt > 0 && vault.deposited > 0
62
72
  })
63
73
 
64
74
  // Sort them
@@ -79,27 +89,30 @@ export async function getLinkedListAccounts(
79
89
 
80
90
  // Pretty print all the vaults before the operation
81
91
  // console.log('Sorted open vaults BEFORE at index:', indexBefore)
82
- let correctOrderBefore = true
83
- for (let i = 0; i < vaults.length; i++) {
84
- if (i < vaults.length - 1) {
85
- // Verify i points to i+1
86
- if (vaults[i].nextVaultToRedeem.toString() !== vaults[i+1].publicKey.toString()){
87
- correctOrderBefore = false
88
- console.log("A vault was found OUT OF ORDER!!", vaults[i])
89
- }
90
- }
91
- }
92
- if (correctOrderBefore){
93
- console.log(`Verfied the on-chain order of vault type:`, vaultTypeAccount.collateralType)
94
- } else {
95
- throw new Error("On-Chian vaults not in order!");
96
- }
92
+ // let correctOrderBefore = true
93
+ // for (let i = 0; i < vaults.length; i++) {
94
+ // if (i < vaults.length - 1) {
95
+ // // Verify i points to i+1
96
+ // if (vaults[i].nextVaultToRedeem.toString() !== vaults[i + 1].publicKey.toString()) {
97
+ // correctOrderBefore = false
98
+ // console.log('A vault was found OUT OF ORDER!!', vaults[i])
99
+ // }
100
+ // }
101
+ // }
102
+ // if (correctOrderBefore) {
103
+ // console.log(`Verfied the on-chain order of vault type:`, vaultTypeAccount.collateralType)
104
+ // } else {
105
+ // throw new Error('On-Chian vaults not in order!')
106
+ // }
97
107
 
98
108
  // If it wasn't in the list, add it now
99
109
  if (indexBefore < 0) {
100
110
  // console.log('Was not in the list before. Adding now.')
101
111
  vaults.push(thisVault)
102
112
  indexBefore = vaults.length - 1
113
+ } else {
114
+ // Copy in the vault so we have the full data (needed to run updateDebtAndCollateral)
115
+ vaults[indexBefore] = thisVault
103
116
  }
104
117
 
105
118
  // Now that we know it's def in the list, iterate the list and update
@@ -147,8 +160,8 @@ export async function getLinkedListAccounts(
147
160
  // )
148
161
 
149
162
  // Print where it moved from / to
150
- // console.log('Index Before', indexBefore)
151
- // console.log('Index After', indexAfter)
163
+ console.log('Index Before', indexBefore)
164
+ console.log('Index After', indexAfter)
152
165
 
153
166
  // Save references to the new left and right
154
167
  if (indexAfter > 0) {
@@ -176,3 +189,33 @@ function sortVaults(a: VaultAccount, b: VaultAccount) {
176
189
  }
177
190
  return aRatio - bRatio
178
191
  }
192
+
193
+ async function getMiniVaults(program: Program<Vault>, collateralType: string) {
194
+ const filters = [
195
+ // Filter for Vault Accounts
196
+ {
197
+ // @ts-ignore
198
+ memcmp: program.account.vault.coder.accounts.memcmp(program.account.vault._idlAccount.name),
199
+ },
200
+ // Filter for Vaults with this collateral type
201
+ {
202
+ memcmp: {
203
+ bytes: base58.encode(VaultAccount.getBufferForString(collateralType)),
204
+ offset: 8 + 32 + 24,
205
+ },
206
+ },
207
+ ]
208
+ const allAccounts = await program.provider.connection.getProgramAccounts(HEDGE_PROGRAM_PUBLICKEY, {
209
+ filters: filters,
210
+ // Slice the data only to grab the 3 u64's of size 8 bytes each
211
+ dataSlice: {
212
+ // See programs/hedge-vault/src/account_data/vault.rs for struct layout
213
+ offset: 8 + 32,
214
+ length: 24,
215
+ },
216
+ })
217
+
218
+ return allAccounts.map(vaultData=>{
219
+ return VaultAccount.FromMiniSlice(vaultData.account.data, vaultData.pubkey)
220
+ })
221
+ }