@exodus/solana-api 1.2.6 → 1.2.7
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/package.json +3 -3
- package/src/index.js +113 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "Exodus internal Solana asset API wrapper",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@exodus/asset-json-rpc": "^1.0.0",
|
|
17
|
-
"@exodus/solana-lib": "^1.2.
|
|
17
|
+
"@exodus/solana-lib": "^1.2.7",
|
|
18
18
|
"lodash": "^4.17.11",
|
|
19
19
|
"wretch": "^1.5.2"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"node-fetch": "~1.6.3"
|
|
23
23
|
},
|
|
24
|
-
"gitHead": "
|
|
24
|
+
"gitHead": "892c55db784616256e065a2c931a5e5611f5404f"
|
|
25
25
|
}
|
package/src/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
import createApi from '@exodus/asset-json-rpc'
|
|
3
|
-
import { tokens, SYSTEM_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@exodus/solana-lib'
|
|
3
|
+
import { tokens, SYSTEM_PROGRAM_ID, STAKE_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@exodus/solana-lib'
|
|
4
4
|
import assert from 'assert'
|
|
5
5
|
import lodash from 'lodash'
|
|
6
6
|
|
|
7
7
|
// Doc: https://docs.solana.com/apps/jsonrpc-api
|
|
8
8
|
|
|
9
|
-
const RPC_URL = 'https://vip-api.mainnet-beta.solana.com
|
|
9
|
+
const RPC_URL = 'https://solana.a.exodus.io' // https://vip-api.mainnet-beta.solana.com/, https://api.mainnet-beta.solana.com, https://solana-api.projectserum.com
|
|
10
10
|
|
|
11
11
|
// Tokens + SOL api support
|
|
12
12
|
class Api {
|
|
@@ -19,6 +19,21 @@ class Api {
|
|
|
19
19
|
this.api = createApi(this.rpcUrl)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
async getCurrentEpoch(): number {
|
|
23
|
+
const { epoch } = await this.api.post({
|
|
24
|
+
method: 'getEpochInfo',
|
|
25
|
+
})
|
|
26
|
+
return Number(epoch)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async getStakeActivation(address): string {
|
|
30
|
+
const { state } = await this.api.post({
|
|
31
|
+
method: 'getStakeActivation',
|
|
32
|
+
params: [address],
|
|
33
|
+
})
|
|
34
|
+
return state
|
|
35
|
+
}
|
|
36
|
+
|
|
22
37
|
async getRecentBlockHash(): string {
|
|
23
38
|
const {
|
|
24
39
|
value: { blockhash },
|
|
@@ -88,8 +103,6 @@ class Api {
|
|
|
88
103
|
.map(({ tokenAccountAddress }) => tokenAccountAddress)
|
|
89
104
|
const accountsToCheck = [address, ...tokenAccountAddresses]
|
|
90
105
|
|
|
91
|
-
console.log('accountsToCheck::', accountsToCheck)
|
|
92
|
-
|
|
93
106
|
const txsResultsByAccount = await Promise.all(
|
|
94
107
|
accountsToCheck.map((addr) =>
|
|
95
108
|
this.getConfirmedSignaturesForAddress(addr, {
|
|
@@ -149,8 +162,11 @@ class Api {
|
|
|
149
162
|
...ix.parsed.info,
|
|
150
163
|
}))
|
|
151
164
|
|
|
152
|
-
const solanaTx = lodash.find(instructions, { program: 'system', type: 'transfer' }) // get SOL transfer
|
|
153
165
|
// program:type tells us if it's a SOL or Token transfer
|
|
166
|
+
const solanaTx = lodash.find(instructions, { program: 'system', type: 'transfer' }) // get SOL transfer
|
|
167
|
+
const stakeTx = lodash.find(instructions, { program: 'system', type: 'createAccountWithSeed' })
|
|
168
|
+
const stakeWithdraw = lodash.find(instructions, { program: 'stake', type: 'withdraw' })
|
|
169
|
+
const stakeUndelegate = lodash.find(instructions, { program: 'stake', type: 'deactivate' })
|
|
154
170
|
|
|
155
171
|
let tx
|
|
156
172
|
if (solanaTx) {
|
|
@@ -163,6 +179,47 @@ class Api {
|
|
|
163
179
|
amount: solanaTx.lamports, // number
|
|
164
180
|
fee: isSending ? fee : 0,
|
|
165
181
|
}
|
|
182
|
+
} else if (stakeTx) {
|
|
183
|
+
// start staking
|
|
184
|
+
tx = {
|
|
185
|
+
owner: stakeTx.base,
|
|
186
|
+
from: stakeTx.base,
|
|
187
|
+
to: stakeTx.owner,
|
|
188
|
+
amount: stakeTx.lamports,
|
|
189
|
+
fee,
|
|
190
|
+
staking: {
|
|
191
|
+
method: 'createAccountWithSeed',
|
|
192
|
+
seed: stakeTx.seed,
|
|
193
|
+
stakeAddress: stakeTx.newAccount,
|
|
194
|
+
stake: stakeTx.lamports,
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
} else if (stakeWithdraw) {
|
|
198
|
+
// TODO: lodash.find above returns 1 occurence, there could be multiple withdraw instructions in the same tx.
|
|
199
|
+
tx = {
|
|
200
|
+
owner: stakeWithdraw.withdrawAuthority,
|
|
201
|
+
from: stakeWithdraw.stakeAccount,
|
|
202
|
+
to: stakeWithdraw.destination,
|
|
203
|
+
amount: stakeWithdraw.lamports,
|
|
204
|
+
fee,
|
|
205
|
+
staking: {
|
|
206
|
+
method: 'withdraw',
|
|
207
|
+
stakeAddress: stakeWithdraw.stakeAccount,
|
|
208
|
+
stake: stakeWithdraw.lamports,
|
|
209
|
+
},
|
|
210
|
+
}
|
|
211
|
+
} else if (stakeUndelegate) {
|
|
212
|
+
tx = {
|
|
213
|
+
owner: stakeUndelegate.stakeAuthority,
|
|
214
|
+
from: stakeUndelegate.stakeAuthority,
|
|
215
|
+
to: stakeUndelegate.stakeAccount,
|
|
216
|
+
amount: 0,
|
|
217
|
+
fee,
|
|
218
|
+
staking: {
|
|
219
|
+
method: 'undelegate',
|
|
220
|
+
stakeAddress: stakeUndelegate.stakeAccount,
|
|
221
|
+
},
|
|
222
|
+
}
|
|
166
223
|
} else {
|
|
167
224
|
// Token tx
|
|
168
225
|
assert.ok(
|
|
@@ -247,11 +304,12 @@ class Api {
|
|
|
247
304
|
: tokenAccounts
|
|
248
305
|
}
|
|
249
306
|
|
|
250
|
-
async getTokensBalance(address: string) {
|
|
307
|
+
async getTokensBalance(address: string, filterByTokens = []) {
|
|
251
308
|
let accounts = await this.getTokenAccountsByOwner(address) // Tokens
|
|
252
309
|
|
|
253
310
|
const tokensBalance = accounts.reduce((acc, { tokenName, balance }) => {
|
|
254
|
-
if (tokenName === 'unknown'
|
|
311
|
+
if (tokenName === 'unknown' || (filterByTokens.length && !filterByTokens.includes(tokenName)))
|
|
312
|
+
return acc // filter by supported tokens only
|
|
255
313
|
if (!acc[tokenName]) acc[tokenName] = Number(balance)
|
|
256
314
|
// e.g { 'serum': 123 }
|
|
257
315
|
else acc[tokenName] += Number(balance) // merge same token account balance
|
|
@@ -306,6 +364,54 @@ class Api {
|
|
|
306
364
|
return type === 'solana'
|
|
307
365
|
}
|
|
308
366
|
|
|
367
|
+
async getStakeAccountsInfo(address: string) {
|
|
368
|
+
// get staked amount and other info
|
|
369
|
+
const res = await this.api.post({
|
|
370
|
+
method: 'getProgramAccounts',
|
|
371
|
+
params: [
|
|
372
|
+
STAKE_PROGRAM_ID.toBase58(),
|
|
373
|
+
{
|
|
374
|
+
filters: [
|
|
375
|
+
{
|
|
376
|
+
memcmp: {
|
|
377
|
+
offset: 12,
|
|
378
|
+
bytes: address,
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
encoding: 'jsonParsed',
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
})
|
|
386
|
+
const accounts = {}
|
|
387
|
+
let totalStake = 0
|
|
388
|
+
let locked = 0
|
|
389
|
+
let withdrawable = 0
|
|
390
|
+
let pending = 0
|
|
391
|
+
for (let entry of res) {
|
|
392
|
+
const addr = entry.pubkey
|
|
393
|
+
const lamports = lodash.get(entry, 'account.lamports', 0)
|
|
394
|
+
const delegation = lodash.get(entry, 'account.data.parsed.info.stake.delegation', {})
|
|
395
|
+
// could have no delegation if the created stake address did not perform a delegate transaction
|
|
396
|
+
|
|
397
|
+
accounts[addr] = delegation
|
|
398
|
+
accounts[addr].lamports = lamports // sol balance
|
|
399
|
+
accounts[addr].activationEpoch = Number(accounts[addr].activationEpoch) || 0
|
|
400
|
+
accounts[addr].deactivationEpoch = Number(accounts[addr].deactivationEpoch) || 0
|
|
401
|
+
let state = 'inactive'
|
|
402
|
+
if (delegation.activationEpoch) state = await this.getStakeActivation(addr)
|
|
403
|
+
accounts[addr].state = state
|
|
404
|
+
accounts[addr].isDeactivating = state === 'deactivating'
|
|
405
|
+
accounts[addr].canWithdraw = state === 'inactive'
|
|
406
|
+
accounts[addr].stake = Number(accounts[addr].stake) || 0 // active staked amount
|
|
407
|
+
totalStake += accounts[addr].stake
|
|
408
|
+
locked += accounts[addr].canWithdraw ? 0 : lamports
|
|
409
|
+
withdrawable += accounts[addr].canWithdraw ? lamports : 0
|
|
410
|
+
pending += accounts[addr].isDeactivating ? lamports : 0
|
|
411
|
+
}
|
|
412
|
+
return { accounts, totalStake, locked, withdrawable, pending }
|
|
413
|
+
}
|
|
414
|
+
|
|
309
415
|
/**
|
|
310
416
|
* Broadcast a signed transaction
|
|
311
417
|
*/
|