@exodus/solana-api 2.5.16 → 2.5.17
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 +10 -7
- package/src/api.js +39 -44
- package/src/index.js +1 -0
- package/src/tx-log/solana-monitor.js +2 -1
- package/src/tx-send.js +202 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.17",
|
|
4
4
|
"description": "Exodus internal Solana asset API wrapper",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@exodus/asset-json-rpc": "^1.0.0",
|
|
19
|
-
"@exodus/asset-lib": "^
|
|
20
|
-
"@exodus/assets": "^
|
|
21
|
-
"@exodus/basic-utils": "^1.
|
|
19
|
+
"@exodus/asset-lib": "^4.0.0",
|
|
20
|
+
"@exodus/assets": "^9.0.1",
|
|
21
|
+
"@exodus/basic-utils": "^2.1.0",
|
|
22
22
|
"@exodus/fetch": "^1.2.0",
|
|
23
|
-
"@exodus/models": "^
|
|
23
|
+
"@exodus/models": "^10.1.0",
|
|
24
24
|
"@exodus/nfts-core": "^0.5.0",
|
|
25
25
|
"@exodus/simple-retry": "^0.0.6",
|
|
26
|
-
"@exodus/solana-lib": "^1.6.
|
|
26
|
+
"@exodus/solana-lib": "^1.6.8",
|
|
27
27
|
"@exodus/solana-meta": "^1.0.3",
|
|
28
28
|
"bn.js": "^4.11.0",
|
|
29
29
|
"debug": "^4.1.1",
|
|
@@ -31,5 +31,8 @@
|
|
|
31
31
|
"url-join": "4.0.0",
|
|
32
32
|
"wretch": "^1.5.2"
|
|
33
33
|
},
|
|
34
|
-
"
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@exodus/assets-testing": "file:../../../__testing__"
|
|
36
|
+
},
|
|
37
|
+
"gitHead": "846ed76714355879216f43c6be8ec2b072169635"
|
|
35
38
|
}
|
package/src/api.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import BN from 'bn.js'
|
|
3
2
|
import createApi from '@exodus/asset-json-rpc'
|
|
4
3
|
import { retry } from '@exodus/simple-retry'
|
|
@@ -12,13 +11,12 @@ import {
|
|
|
12
11
|
TOKEN_PROGRAM_ID,
|
|
13
12
|
SOL_DECIMAL,
|
|
14
13
|
computeBalance,
|
|
15
|
-
SolanaWeb3Message,
|
|
16
14
|
buildRawTransaction,
|
|
17
15
|
} from '@exodus/solana-lib'
|
|
18
16
|
import assert from 'assert'
|
|
19
17
|
import lodash from 'lodash'
|
|
20
18
|
import urljoin from 'url-join'
|
|
21
|
-
import wretch
|
|
19
|
+
import wretch from 'wretch'
|
|
22
20
|
import { magicEden } from '@exodus/nfts-core'
|
|
23
21
|
import { Connection } from './connection'
|
|
24
22
|
|
|
@@ -51,7 +49,7 @@ export class Api {
|
|
|
51
49
|
this.tokens = new Map(Object.values(solTokens).map((v) => [v.mintAddress, v]))
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
request(path, contentType = 'application/json')
|
|
52
|
+
request(path, contentType = 'application/json') {
|
|
55
53
|
return wretch(urljoin(this.rpcUrl, path)).headers({
|
|
56
54
|
'Content-type': contentType,
|
|
57
55
|
})
|
|
@@ -101,25 +99,25 @@ export class Api {
|
|
|
101
99
|
return this.api.post({ method, params })
|
|
102
100
|
}
|
|
103
101
|
|
|
104
|
-
getTokenByAddress(mint
|
|
102
|
+
getTokenByAddress(mint) {
|
|
105
103
|
return this.tokens.get(mint)
|
|
106
104
|
}
|
|
107
105
|
|
|
108
|
-
isTokenSupported(mint
|
|
106
|
+
isTokenSupported(mint) {
|
|
109
107
|
return this.tokens.has(mint)
|
|
110
108
|
}
|
|
111
109
|
|
|
112
|
-
async getEpochInfo()
|
|
110
|
+
async getEpochInfo() {
|
|
113
111
|
const { epoch } = await this.rpcCall('getEpochInfo')
|
|
114
112
|
return Number(epoch)
|
|
115
113
|
}
|
|
116
114
|
|
|
117
|
-
async getStakeActivation(address)
|
|
115
|
+
async getStakeActivation(address) {
|
|
118
116
|
const { state } = await this.rpcCall('getStakeActivation', [address])
|
|
119
117
|
return state
|
|
120
118
|
}
|
|
121
119
|
|
|
122
|
-
async getRecentBlockHash(commitment
|
|
120
|
+
async getRecentBlockHash(commitment?) {
|
|
123
121
|
const result = await this.rpcCall(
|
|
124
122
|
'getRecentBlockhash',
|
|
125
123
|
[{ commitment: commitment || 'finalized', encoding: 'jsonParsed' }],
|
|
@@ -129,33 +127,33 @@ export class Api {
|
|
|
129
127
|
}
|
|
130
128
|
|
|
131
129
|
// Transaction structure: https://docs.solana.com/apps/jsonrpc-api#transaction-structure
|
|
132
|
-
async getTransactionById(id
|
|
130
|
+
async getTransactionById(id) {
|
|
133
131
|
return this.rpcCall('getTransaction', [
|
|
134
132
|
id,
|
|
135
133
|
{ encoding: 'jsonParsed', maxSupportedTransactionVersion: 0 },
|
|
136
134
|
])
|
|
137
135
|
}
|
|
138
136
|
|
|
139
|
-
async getFee()
|
|
137
|
+
async getFee() {
|
|
140
138
|
const result = await this.rpcCall('getRecentBlockhash', [
|
|
141
139
|
{ commitment: 'finalized', encoding: 'jsonParsed' },
|
|
142
140
|
])
|
|
143
141
|
return lodash.get(result, 'value.feeCalculator.lamportsPerSignature')
|
|
144
142
|
}
|
|
145
143
|
|
|
146
|
-
async getBalance(address
|
|
144
|
+
async getBalance(address) {
|
|
147
145
|
const result = await this.rpcCall('getBalance', [address, { encoding: 'jsonParsed' }], {
|
|
148
146
|
address,
|
|
149
147
|
})
|
|
150
148
|
return lodash.get(result, 'value', 0)
|
|
151
149
|
}
|
|
152
150
|
|
|
153
|
-
async getBlockTime(slot
|
|
151
|
+
async getBlockTime(slot) {
|
|
154
152
|
// might result in error if executed on a validator with partial ledger (https://github.com/solana-labs/solana/issues/12413)
|
|
155
153
|
return this.rpcCall('getBlockTime', [slot])
|
|
156
154
|
}
|
|
157
155
|
|
|
158
|
-
async getConfirmedSignaturesForAddress(address
|
|
156
|
+
async getConfirmedSignaturesForAddress(address, { until, before, limit } = {}) {
|
|
159
157
|
until = until || undefined
|
|
160
158
|
return this.rpcCall('getSignaturesForAddress', [address, { until, before, limit }], { address })
|
|
161
159
|
}
|
|
@@ -163,10 +161,7 @@ export class Api {
|
|
|
163
161
|
/**
|
|
164
162
|
* Get transactions from an address
|
|
165
163
|
*/
|
|
166
|
-
async getTransactions(
|
|
167
|
-
address: string,
|
|
168
|
-
{ cursor, before, limit, includeUnparsed = false } = {}
|
|
169
|
-
): any {
|
|
164
|
+
async getTransactions(address, { cursor, before, limit, includeUnparsed = false } = {}) {
|
|
170
165
|
let transactions = []
|
|
171
166
|
// cursor is a txHash
|
|
172
167
|
|
|
@@ -233,11 +228,11 @@ export class Api {
|
|
|
233
228
|
}
|
|
234
229
|
|
|
235
230
|
parseTransaction(
|
|
236
|
-
ownerAddress
|
|
237
|
-
txDetails
|
|
238
|
-
tokenAccountsByOwner
|
|
231
|
+
ownerAddress,
|
|
232
|
+
txDetails,
|
|
233
|
+
tokenAccountsByOwner,
|
|
239
234
|
{ includeUnparsed = false } = {}
|
|
240
|
-
)
|
|
235
|
+
) {
|
|
241
236
|
let {
|
|
242
237
|
fee,
|
|
243
238
|
preBalances,
|
|
@@ -563,7 +558,7 @@ export class Api {
|
|
|
563
558
|
}
|
|
564
559
|
}
|
|
565
560
|
|
|
566
|
-
async getSupply(mintAddress
|
|
561
|
+
async getSupply(mintAddress) {
|
|
567
562
|
const result = await this.rpcCall('getTokenSupply', [mintAddress])
|
|
568
563
|
return lodash.get(result, 'value.amount')
|
|
569
564
|
}
|
|
@@ -590,7 +585,7 @@ export class Api {
|
|
|
590
585
|
return tokensMint
|
|
591
586
|
}
|
|
592
587
|
|
|
593
|
-
async getTokenAccountsByOwner(address
|
|
588
|
+
async getTokenAccountsByOwner(address, tokenTicker) {
|
|
594
589
|
const { value: accountsList } = await this.rpcCall(
|
|
595
590
|
'getTokenAccountsByOwner',
|
|
596
591
|
[address, { programId: TOKEN_PROGRAM_ID.toBase58() }, { encoding: 'jsonParsed' }],
|
|
@@ -637,7 +632,7 @@ export class Api {
|
|
|
637
632
|
return tokensBalance
|
|
638
633
|
}
|
|
639
634
|
|
|
640
|
-
async isAssociatedTokenAccountActive(tokenAddress
|
|
635
|
+
async isAssociatedTokenAccountActive(tokenAddress) {
|
|
641
636
|
// Returns the token balance of an SPL Token account.
|
|
642
637
|
try {
|
|
643
638
|
await this.rpcCall('getTokenAccountBalance', [tokenAddress])
|
|
@@ -648,40 +643,40 @@ export class Api {
|
|
|
648
643
|
}
|
|
649
644
|
|
|
650
645
|
// Returns account balance of a SPL Token account.
|
|
651
|
-
async getTokenBalance(tokenAddress
|
|
646
|
+
async getTokenBalance(tokenAddress) {
|
|
652
647
|
const result = await this.rpcCall('getTokenAccountBalance', [tokenAddress])
|
|
653
648
|
return lodash.get(result, 'value.amount')
|
|
654
649
|
}
|
|
655
650
|
|
|
656
|
-
async getAccountInfo(address
|
|
651
|
+
async getAccountInfo(address, encoding = 'jsonParsed') {
|
|
657
652
|
const { value } = await this.rpcCall(
|
|
658
653
|
'getAccountInfo',
|
|
659
|
-
[address, { encoding
|
|
654
|
+
[address, { encoding, commitment: 'single' }],
|
|
660
655
|
{ address }
|
|
661
656
|
)
|
|
662
657
|
return value
|
|
663
658
|
}
|
|
664
659
|
|
|
665
|
-
async isSpl(address
|
|
660
|
+
async isSpl(address) {
|
|
666
661
|
const { owner } = await this.getAccountInfo(address)
|
|
667
662
|
return owner === 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
|
|
668
663
|
}
|
|
669
664
|
|
|
670
|
-
async getMetaplexMetadata(tokenMintAddress
|
|
665
|
+
async getMetaplexMetadata(tokenMintAddress) {
|
|
671
666
|
const metaplexPDA = getMetadataAccount(tokenMintAddress)
|
|
672
|
-
const res = await this.getAccountInfo(metaplexPDA)
|
|
667
|
+
const res = await this.getAccountInfo(metaplexPDA, 'base64')
|
|
673
668
|
const data = lodash.get(res, 'data[0]')
|
|
674
669
|
if (!data) return null
|
|
675
670
|
|
|
676
671
|
return deserializeMetaplexMetadata(Buffer.from(data, 'base64'))
|
|
677
672
|
}
|
|
678
673
|
|
|
679
|
-
async getDecimals(tokenMintAddress
|
|
674
|
+
async getDecimals(tokenMintAddress) {
|
|
680
675
|
const result = await this.rpcCall('getTokenSupply', [tokenMintAddress])
|
|
681
676
|
return lodash.get(result, 'value.decimals', null)
|
|
682
677
|
}
|
|
683
678
|
|
|
684
|
-
async getAddressType(address
|
|
679
|
+
async getAddressType(address) {
|
|
685
680
|
// solana, token or null (unknown), meaning address has never been initialized
|
|
686
681
|
const value = await this.getAccountInfo(address)
|
|
687
682
|
if (value === null) return null
|
|
@@ -699,7 +694,7 @@ export class Api {
|
|
|
699
694
|
: null
|
|
700
695
|
}
|
|
701
696
|
|
|
702
|
-
async getTokenAddressOwner(address
|
|
697
|
+
async getTokenAddressOwner(address) {
|
|
703
698
|
const value = await this.getAccountInfo(address)
|
|
704
699
|
const owner = lodash.get(value, 'data.parsed.info.owner', null)
|
|
705
700
|
return owner
|
|
@@ -711,17 +706,17 @@ export class Api {
|
|
|
711
706
|
return mintAddress
|
|
712
707
|
}
|
|
713
708
|
|
|
714
|
-
async isTokenAddress(address
|
|
709
|
+
async isTokenAddress(address) {
|
|
715
710
|
const type = await this.getAddressType(address)
|
|
716
711
|
return type === 'token'
|
|
717
712
|
}
|
|
718
713
|
|
|
719
|
-
async isSOLaddress(address
|
|
714
|
+
async isSOLaddress(address) {
|
|
720
715
|
const type = await this.getAddressType(address)
|
|
721
716
|
return type === 'solana'
|
|
722
717
|
}
|
|
723
718
|
|
|
724
|
-
async getStakeAccountsInfo(address
|
|
719
|
+
async getStakeAccountsInfo(address) {
|
|
725
720
|
const params = [
|
|
726
721
|
STAKE_PROGRAM_ID.toBase58(),
|
|
727
722
|
{
|
|
@@ -785,15 +780,15 @@ export class Api {
|
|
|
785
780
|
return earnings
|
|
786
781
|
}
|
|
787
782
|
|
|
788
|
-
async getMinimumBalanceForRentExemption(size
|
|
783
|
+
async getMinimumBalanceForRentExemption(size) {
|
|
789
784
|
return this.rpcCall('getMinimumBalanceForRentExemption', [size])
|
|
790
785
|
}
|
|
791
786
|
|
|
792
|
-
async getProgramAccounts(programId
|
|
787
|
+
async getProgramAccounts(programId, config) {
|
|
793
788
|
return this.rpcCall('getProgramAccounts', [programId, config])
|
|
794
789
|
}
|
|
795
790
|
|
|
796
|
-
async getMultipleAccounts(pubkeys
|
|
791
|
+
async getMultipleAccounts(pubkeys, config) {
|
|
797
792
|
const response = await this.rpcCall('getMultipleAccounts', [pubkeys, config])
|
|
798
793
|
return response && response.value ? response.value : []
|
|
799
794
|
}
|
|
@@ -801,7 +796,7 @@ export class Api {
|
|
|
801
796
|
/**
|
|
802
797
|
* Broadcast a signed transaction
|
|
803
798
|
*/
|
|
804
|
-
broadcastTransaction = async (signedTx
|
|
799
|
+
broadcastTransaction = async (signedTx, options) => {
|
|
805
800
|
console.log('Solana broadcasting TX:', signedTx) // base64
|
|
806
801
|
const defaultOptions = { encoding: 'base64', preflightCommitment: 'finalized' }
|
|
807
802
|
|
|
@@ -955,9 +950,9 @@ export class Api {
|
|
|
955
950
|
* Simulate transaction and return side effects
|
|
956
951
|
*/
|
|
957
952
|
simulateAndRetrieveSideEffects = async (
|
|
958
|
-
message
|
|
959
|
-
publicKey
|
|
960
|
-
transactionMessage
|
|
953
|
+
message,
|
|
954
|
+
publicKey,
|
|
955
|
+
transactionMessage? // decompiled TransactionMessage
|
|
961
956
|
) => {
|
|
962
957
|
const { config, accountAddresses } = getTransactionSimulationParams(
|
|
963
958
|
transactionMessage || message
|
package/src/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export { default as SolanaFeeMonitor } from './fee-monitor'
|
|
|
8
8
|
export * from './api'
|
|
9
9
|
export * from './tx-log'
|
|
10
10
|
export * from './account-state'
|
|
11
|
+
export * from './tx-send'
|
|
11
12
|
|
|
12
13
|
// These are not the same asset objects as the wallet creates, so they should never be returned to the wallet.
|
|
13
14
|
// Initially this may be violated by the Solana code until the first monitor tick updates assets with setTokens()
|
|
@@ -134,6 +134,7 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
134
134
|
const assetName = _.get(tx, 'token.tokenName', baseAsset.name)
|
|
135
135
|
const asset = this.assets[assetName]
|
|
136
136
|
if (assetName === 'unknown' || !asset) continue // skip unknown tokens
|
|
137
|
+
const feeAsset = asset.feeAsset
|
|
137
138
|
|
|
138
139
|
const coinAmount = asset.currency.baseUnit(tx.amount).toDefault()
|
|
139
140
|
|
|
@@ -150,6 +151,7 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
150
151
|
unparsed: !!tx.unparsed,
|
|
151
152
|
swapTx: !!(tx.data && tx.data.inner),
|
|
152
153
|
},
|
|
154
|
+
currencies: { [assetName]: asset.currency, [feeAsset.name]: feeAsset.currency },
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
if (tx.owner === address) {
|
|
@@ -172,7 +174,6 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
172
174
|
item.data.meta = tx.data.meta
|
|
173
175
|
}
|
|
174
176
|
if (asset.assetType === 'SOLANA_TOKEN' && item.feeAmount && item.feeAmount.isPositive) {
|
|
175
|
-
const feeAsset = asset.feeAsset
|
|
176
177
|
const feeItem = {
|
|
177
178
|
..._.clone(item),
|
|
178
179
|
coinName: feeAsset.name,
|
package/src/tx-send.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { createUnsignedTx, findAssociatedTokenAddress } from '@exodus/solana-lib'
|
|
2
|
+
import assert from 'minimalistic-assert'
|
|
3
|
+
|
|
4
|
+
export const createAndBroadcastTXFactory = (api) => async (
|
|
5
|
+
{ asset, walletAccount, address, amount, options = {} },
|
|
6
|
+
{ assetClientInterface }
|
|
7
|
+
) => {
|
|
8
|
+
const assetName = asset.name
|
|
9
|
+
assert(assetClientInterface, `assetClientInterface must be supplied in sendTx for ${assetName}`)
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
feeAmount,
|
|
13
|
+
shouldLog = true,
|
|
14
|
+
method,
|
|
15
|
+
stakeAddresses,
|
|
16
|
+
seed,
|
|
17
|
+
pool,
|
|
18
|
+
customMintAddress,
|
|
19
|
+
tokenStandard,
|
|
20
|
+
// <MagicEden>
|
|
21
|
+
initializerAddress,
|
|
22
|
+
initializerDepositTokenAddress,
|
|
23
|
+
takerAmount,
|
|
24
|
+
escrowAddress,
|
|
25
|
+
escrowBump,
|
|
26
|
+
pdaAddress,
|
|
27
|
+
takerAddress,
|
|
28
|
+
expectedTakerAmount,
|
|
29
|
+
expectedMintAddress,
|
|
30
|
+
metadataAddress,
|
|
31
|
+
creators,
|
|
32
|
+
// </MagicEden>
|
|
33
|
+
reference,
|
|
34
|
+
memo,
|
|
35
|
+
} = options
|
|
36
|
+
let { recentBlockhash } = options
|
|
37
|
+
const { baseAsset } = asset
|
|
38
|
+
const from = await assetClientInterface.getReceiveAddress({
|
|
39
|
+
assetName: baseAsset.name,
|
|
40
|
+
walletAccount,
|
|
41
|
+
})
|
|
42
|
+
const currentAccountState = await assetClientInterface.getAccountState({
|
|
43
|
+
assetName: baseAsset.name,
|
|
44
|
+
walletAccount,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
recentBlockhash = recentBlockhash || (await api.getRecentBlockHash())
|
|
48
|
+
|
|
49
|
+
let tokenParams = {}
|
|
50
|
+
if (asset.assetType === 'SOLANA_TOKEN' || customMintAddress) {
|
|
51
|
+
const tokenMintAddress = customMintAddress || asset.mintAddress
|
|
52
|
+
const tokenAddress = findAssociatedTokenAddress(address, tokenMintAddress)
|
|
53
|
+
const [
|
|
54
|
+
destinationAddressType,
|
|
55
|
+
isAssociatedTokenAccountActive,
|
|
56
|
+
fromTokenAccountAddresses,
|
|
57
|
+
] = await Promise.all([
|
|
58
|
+
api.getAddressType(address),
|
|
59
|
+
api.isAssociatedTokenAccountActive(tokenAddress),
|
|
60
|
+
api.getTokenAccountsByOwner(from),
|
|
61
|
+
])
|
|
62
|
+
|
|
63
|
+
const fromTokenAddresses = fromTokenAccountAddresses.filter(
|
|
64
|
+
({ mintAddress }) => mintAddress === tokenMintAddress
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
tokenParams = {
|
|
68
|
+
tokenMintAddress,
|
|
69
|
+
destinationAddressType,
|
|
70
|
+
isAssociatedTokenAccountActive,
|
|
71
|
+
fromTokenAddresses,
|
|
72
|
+
tokenStandard,
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const stakingParams = {
|
|
77
|
+
method,
|
|
78
|
+
stakeAddresses,
|
|
79
|
+
seed,
|
|
80
|
+
pool,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const magicEdenParams = {
|
|
84
|
+
method,
|
|
85
|
+
initializerAddress,
|
|
86
|
+
initializerDepositTokenAddress,
|
|
87
|
+
takerAmount,
|
|
88
|
+
escrowAddress,
|
|
89
|
+
escrowBump,
|
|
90
|
+
pdaAddress,
|
|
91
|
+
takerAddress,
|
|
92
|
+
expectedTakerAmount,
|
|
93
|
+
expectedMintAddress,
|
|
94
|
+
metadataAddress,
|
|
95
|
+
creators,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const unsignedTransaction = await createUnsignedTx({
|
|
99
|
+
asset,
|
|
100
|
+
from,
|
|
101
|
+
to: address,
|
|
102
|
+
amount,
|
|
103
|
+
fee: feeAmount,
|
|
104
|
+
recentBlockhash,
|
|
105
|
+
reference,
|
|
106
|
+
memo,
|
|
107
|
+
...tokenParams,
|
|
108
|
+
...stakingParams,
|
|
109
|
+
...magicEdenParams,
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
const { txId, rawTx } = await assetClientInterface.signTransaction({
|
|
113
|
+
assetName: baseAsset.name,
|
|
114
|
+
unsignedTx: unsignedTransaction,
|
|
115
|
+
walletAccount,
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
await baseAsset.api.broadcastTx(rawTx)
|
|
119
|
+
|
|
120
|
+
const selfSend = from === address
|
|
121
|
+
const coinAmount = selfSend ? asset.currency.ZERO : amount.abs().negate()
|
|
122
|
+
|
|
123
|
+
if (shouldLog) {
|
|
124
|
+
const tx = {
|
|
125
|
+
txId,
|
|
126
|
+
confirmations: 0,
|
|
127
|
+
coinName: assetName,
|
|
128
|
+
coinAmount,
|
|
129
|
+
feeAmount,
|
|
130
|
+
feeCoinName: asset.feeAsset.name,
|
|
131
|
+
selfSend,
|
|
132
|
+
to: address,
|
|
133
|
+
data: {
|
|
134
|
+
// note
|
|
135
|
+
},
|
|
136
|
+
currencies: { [assetName]: asset.currency, [asset.feeAsset.name]: asset.feeAsset.currency },
|
|
137
|
+
}
|
|
138
|
+
await assetClientInterface.updateTxLogAndNotify({ assetName, walletAccount, txs: [tx] })
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const changes = {}
|
|
142
|
+
if (asset.assetType === 'SOLANA_TOKEN') {
|
|
143
|
+
Object.assign(changes, {
|
|
144
|
+
balance: currentAccountState.balance.sub(feeAmount), // solana balance
|
|
145
|
+
tokenBalances: {
|
|
146
|
+
...currentAccountState.tokenBalances,
|
|
147
|
+
[assetName]: currentAccountState.tokenBalances[assetName].sub(coinAmount.abs()),
|
|
148
|
+
}, // SPL token balance
|
|
149
|
+
})
|
|
150
|
+
// write tx entry in solana for token fee
|
|
151
|
+
const tx = {
|
|
152
|
+
txId,
|
|
153
|
+
coinName: baseAsset.name,
|
|
154
|
+
coinAmount: baseAsset.currency.ZERO,
|
|
155
|
+
tokens: [assetName],
|
|
156
|
+
feeAmount,
|
|
157
|
+
feeCoinName: baseAsset.feeAsset.name,
|
|
158
|
+
to: address,
|
|
159
|
+
selfSend,
|
|
160
|
+
currencies: {
|
|
161
|
+
[baseAsset.name]: baseAsset.currency,
|
|
162
|
+
[baseAsset.feeAsset.name]: baseAsset.feeAsset.currency,
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
await assetClientInterface.updateTxLogAndNotify({ assetName, walletAccount, txs: [tx] })
|
|
166
|
+
} else if (customMintAddress) {
|
|
167
|
+
Object.assign(changes, {
|
|
168
|
+
balance: currentAccountState.balance.sub(feeAmount), // solana balance
|
|
169
|
+
})
|
|
170
|
+
} else if (method) {
|
|
171
|
+
// staking: no changes
|
|
172
|
+
} else {
|
|
173
|
+
// SOL transfer
|
|
174
|
+
Object.assign(changes, {
|
|
175
|
+
balance: currentAccountState.balance.sub(coinAmount.abs()).sub(feeAmount),
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (method) {
|
|
180
|
+
const stakingData = { ...currentAccountState.mem }
|
|
181
|
+
switch (method) {
|
|
182
|
+
case 'delegate':
|
|
183
|
+
stakingData.isDelegating = true
|
|
184
|
+
stakingData.locked = stakingData.locked.add(amount)
|
|
185
|
+
break
|
|
186
|
+
case 'undelegate':
|
|
187
|
+
stakingData.isDelegating = false
|
|
188
|
+
stakingData.pending = stakingData.pending.add(stakingData.locked)
|
|
189
|
+
stakingData.locked = asset.currency.ZERO
|
|
190
|
+
break
|
|
191
|
+
case 'withdraw':
|
|
192
|
+
stakingData.withdrawable = asset.currency.ZERO
|
|
193
|
+
break
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
Object.assign(changes, { mem: stakingData })
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
await assetClientInterface.updateAccountState({ assetName, walletAccount, newData: changes })
|
|
200
|
+
|
|
201
|
+
return { txId }
|
|
202
|
+
}
|