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.
- package/declarations/idl/vault.d.ts +128 -3
- package/declarations/index.d.ts +1 -1
- package/declarations/instructions/updateVaultType.d.ts +15 -0
- package/declarations/state/VaultAccount.d.ts +23 -0
- package/lib/idl/vault.js +128 -3
- package/lib/index.js +1 -1
- package/lib/instructions/updateVaultType.js +47 -0
- package/lib/state/VaultAccount.js +73 -9
- package/lib/utils/Errors.js +1 -0
- package/lib/utils/getLinkedListAccounts.js +78 -38
- package/package.json +3 -2
- package/src/idl/vault.ts +256 -6
- package/src/index.ts +1 -1
- package/src/instructions/{setVaultTypeStatus.ts → updateVaultType.ts} +39 -8
- package/src/state/VaultAccount.ts +61 -13
- package/src/utils/Errors.ts +1 -0
- package/src/utils/getLinkedListAccounts.ts +82 -39
@@ -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
|
-
|
29
|
+
/** Debt redistribution snapshop */
|
30
|
+
debtProductSnapshotBytes = new Decimal(0)
|
28
31
|
|
29
|
-
|
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
|
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
|
47
|
+
this.vaultNumber = vault.vaultNumber?.toNumber()
|
43
48
|
this.pdaSalt = vault.pdaSalt
|
44
|
-
this.deposited = vault.deposited
|
45
|
-
this.denormalizedDebt = vault.denormalizedDebt
|
46
|
-
|
47
|
-
|
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
|
-
|
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
|
-
.
|
148
|
-
|
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
|
}
|
package/src/utils/Errors.ts
CHANGED
@@ -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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
// Load them into our account objects
|
49
|
-
vaults = allVaults.map((vault) => {
|
50
|
-
|
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
|
-
|
55
|
-
|
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.
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
}
|
92
|
-
if (correctOrderBefore){
|
93
|
-
|
94
|
-
} else {
|
95
|
-
|
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
|
-
|
151
|
-
|
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
|
+
}
|