Skip to content

Commit

Permalink
fx
Browse files Browse the repository at this point in the history
  • Loading branch information
Turtus committed May 8, 2024
1 parent 65b0a05 commit 24f3fe4
Showing 1 changed file with 158 additions and 34 deletions.
192 changes: 158 additions & 34 deletions crypto/blockchains/sol/SolScannerProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ import BlocksoftAxios from '@crypto/common/BlocksoftAxios'
import BlocksoftUtils from '@crypto/common/BlocksoftUtils'
import BlocksoftExternalSettings from '@crypto/common/BlocksoftExternalSettings'

import SolTmpDS from '@crypto/blockchains/sol/stores/SolTmpDS'

import config from '@app/config/config'
import SolUtils from '@crypto/blockchains/sol/ext/SolUtils'

const CACHE_FROM_DB = {}
const CACHE_TXS = {}
const CACHE_VALID_TIME = 120000
let CACHE_LAST_BLOCK = 0

export default class SolScannerProcessor {
Expand All @@ -22,7 +26,9 @@ export default class SolScannerProcessor {
/**
* @param {string} address
* @return {Promise<{balance, provider}>}
* https://solana.com/docs/rpc/http/getbalance
* https://docs.solana.com/developing/clients/jsonrpc-api#getaccountinfo
* https://docs.solana.com/developing/clients/jsonrpc-api#getconfirmedsignaturesforaddress2
* curl https://solana-api.projectserum.com -X POST -H "Content-Type: application/json" -d '{'jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["9mnBdsuL1x24HbU4oeNDBAYVAGg2vVndkRAc18kPNqCJ']}'
*/
async getBalanceBlockchain(address) {
address = address.trim()
Expand All @@ -31,6 +37,7 @@ export default class SolScannerProcessor {
let balance = 0
try {
await SolUtils.getEpoch()

const apiPath = BlocksoftExternalSettings.getStatic('SOL_SERVER')
const data = {
'jsonrpc': '2.0',
Expand All @@ -39,6 +46,7 @@ export default class SolScannerProcessor {
'params': [address]
}
const res = await BlocksoftAxios._request(apiPath, 'POST', data)

if (typeof res.data.result === 'undefined' || typeof res.data.result.value === 'undefined') {
return false
}
Expand All @@ -47,9 +55,6 @@ export default class SolScannerProcessor {
}
balance = res.data.result.value
} catch (e) {
if (config.debug.cryptoErrors) {
console.log(this._settings.currencyCode + ' SolScannerProcessor getBalanceBlockchain address ' + address + ' error ' + e.message)
}
BlocksoftCryptoLog.log(this._settings.currencyCode + ' SolScannerProcessor getBalanceBlockchain address ' + address + ' error ' + e.message)
return false
}
Expand All @@ -61,59 +66,61 @@ export default class SolScannerProcessor {
* @param {string} scanData.account.address
* @return {Promise<[UnifiedTransaction]>}
* https://docs.solana.com/developing/clients/jsonrpc-api#getsignaturesforaddress
* https://solana.com/docs/rpc/deprecated/getconfirmedsignaturesforaddress2
**/
* curl https://api.mainnet-beta.solana.com -X POST -H "Content-Type: application/json" -d '{'jsonrpc": "2.0","id": 1,"method": "getConfirmedSignaturesForAddress2","params": ["9mnBdsuL1x24HbU4oeNDBAYVAGg2vVndkRAc18kPNqCJ",{"limit': 1}]}'
*/
async getTransactionsBlockchain(scanData, source) {
const address = scanData.account.address.trim()
const lastHashVar = address + this.tokenAddress
this._cleanCache()
try {
if (typeof CACHE_FROM_DB[lastHashVar] === 'undefined') {
CACHE_FROM_DB[lastHashVar] = await SolTmpDS.getCache(lastHashVar)
}

const data = {
'jsonrpc': '2.0',
'id': 1,
'method': 'getSignaturesForAddress',
'method': 'getConfirmedSignaturesForAddress2',
'params': [
address,
{
'limit': 1
'limit': 100
}
]
}

if (CACHE_FROM_DB[lastHashVar] && typeof CACHE_FROM_DB[lastHashVar]['last_hash'] !== 'undefined') {
data.params[1].until = CACHE_FROM_DB[lastHashVar]['last_hash']
}
const apiPath = BlocksoftExternalSettings.getStatic('SOL_SERVER')
const res = await BlocksoftAxios._request(apiPath, 'POST', data)
if (typeof res.data.result === 'undefined' || !res.data.result) {
return false
}
const transactions = await this._unifyTransactions(address, res.data.result)

const transactions = await this._unifyTransactions(address, res.data.result, lastHashVar)
BlocksoftCryptoLog.log(this._settings.currencyCode + ' SolScannerProcessor.getTransactions finished ' + address)
return transactions
} catch (e) {
if (config.debug.cryptoErrors) {
console.log(this._settings.currencyCode + ' SolScannerProcessor getTransactionsBlockchain address ' + address + ' error ' + e.message)
}
BlocksoftCryptoLog.log(this._settings.currencyCode + ' SolScannerProcessor getTransactionsBlockchain address ' + address + ' error ' + e.message)
return false
}
}

async _unifyTransactions(address, result) {
async _unifyTransactions(address, result, lastHashVar) {
const transactions = []
let lastHash = false
let hasError = false
for (const tx of result) {
try {
const transaction = await this._unifyTransaction(address, tx)
console.log(`
tx `, tx)
console.log(`
=>`, transaction)
if (transaction) {
transactions.push(transaction)
if (transaction.transactionStatus === 'success' && !lastHash && !hasError) {
lastHash = transaction.transactionHash
}
}
} catch (e) {
hasError = true
if (e.message.indexOf('request failed') === -1) {
if (config.debug.appErrors) {
console.log(this._settings.currencyCode + ' SolScannerProcessor._unifyTransactions ' + tx.signature + ' error ' + e.message)
Expand All @@ -122,10 +129,34 @@ export default class SolScannerProcessor {
}
}
}

if (lastHash) {
if (!CACHE_FROM_DB[lastHashVar]) {
CACHE_FROM_DB[lastHashVar] = { 'last_hash': lastHash }
await SolTmpDS.saveCache(lastHashVar, 'last_hash', lastHash)
} else if (typeof CACHE_FROM_DB[lastHashVar]['last_hash'] === 'undefined') {
CACHE_FROM_DB[lastHashVar]['last_hash'] = lastHash
await SolTmpDS.saveCache(lastHashVar, 'last_hash', lastHash)
} else {
CACHE_FROM_DB[lastHashVar]['last_hash'] = lastHash
await SolTmpDS.updateCache(lastHashVar, 'last_hash', lastHash)
}
}
return transactions
}

_cleanCache() {
const now = new Date().getTime()
for (const key in CACHE_TXS) {
const t = (now - CACHE_TXS[key].now)
if (t > CACHE_VALID_TIME) {
delete CACHE_TXS[key]
}
}
}

async _unifyTransaction(address, transaction) {

const data = {
'jsonrpc': '2.0',
'id': 1,
Expand All @@ -145,7 +176,7 @@ export default class SolScannerProcessor {
return false
}
additional = res.data.result
CACHE_TXS[transaction.signature] = {data : additional, now : new Date().getTime(), found : new Date().getTime() }
CACHE_TXS[transaction.signature] = {data : additional, now : new Date().getTime() }
} catch (e) {
if (config.debug.cryptoErrors) {
console.log(this._settings.currencyCode + ' SolScannerProcessor._unifyTransaction ' + transaction.signature + ' request error ' + e.message)
Expand All @@ -154,17 +185,110 @@ export default class SolScannerProcessor {
}
} else {
additional = CACHE_TXS[transaction.signature].data
CACHE_TXS[transaction.signature].found = new Date().getTime()
}

console.log(JSON.stringify(additional))
return false
let addressFrom = ''
let addressTo = ''
let anySigner = ''
let addressFrom = false
let addressTo = false
let addressAmount = 0
let addressAmountPlus = 0
let anyFromAddress = false
let anyToAddress = false

const indexedPre = {}
const indexedPost = {}
const indexedCreated = {}
const indexedAssociated = {}

if (this.tokenAddress) {
for (const tmp of additional.meta.preTokenBalances) {
if (tmp.mint !== this.tokenAddress) continue
const realIndex = tmp.accountIndex
indexedPre[realIndex] = tmp.uiTokenAmount.amount
}

for (const tmp of additional.meta.postTokenBalances) {
if (tmp.mint !== this.tokenAddress) continue
const realIndex = tmp.accountIndex
indexedPost[realIndex] = tmp.uiTokenAmount.amount
}

for (const tmp of additional.transaction.message.instructions) {
if (tmp.program !== 'spl-associated-token-account') continue
indexedCreated[tmp.parsed.info.account] = tmp.parsed.info.wallet
}

for (let i = 0, ic = additional.transaction.message.accountKeys.length; i < ic; i++) {
const tmpAddress = additional.transaction.message.accountKeys[i]
if (tmpAddress.pubkey === '11111111111111111111111111111111') continue
const sourceAssociatedTokenAddress = await SolUtils.findAssociatedTokenAddress(
tmpAddress.pubkey,
this.tokenAddress
)
indexedAssociated[sourceAssociatedTokenAddress] = tmpAddress
}
} else {
// do nothing!
}

let anySigner = false
let addressAmountPlus = false
for (let i = 0, ic = additional.transaction.message.accountKeys.length; i < ic; i++) {
let tmpAddress = additional.transaction.message.accountKeys[i]
if (tmpAddress.pubkey === '11111111111111111111111111111111') continue
let tmpAmount = '0'
if (typeof indexedAssociated[tmpAddress.pubkey] !== 'undefined') {
tmpAddress = indexedAssociated[tmpAddress.pubkey]
}
if (this.tokenAddress) {
const to = typeof indexedPost[i] !== 'undefined' ? indexedPost[i] : 0
const from = typeof indexedPre[i] !== 'undefined' ? indexedPre[i] : 0
tmpAmount = BlocksoftUtils.diff(to, from).toString()
} else {
tmpAmount = BlocksoftUtils.diff(additional.meta.postBalances[i], additional.meta.preBalances[i]).toString()
}

if (tmpAddress.pubkey && tmpAddress.signer) {
anySigner = tmpAddress.pubkey
}

if (tmpAmount === '0') continue

if (tmpAddress.pubkey === address ||
(
typeof indexedCreated[tmpAddress.pubkey] !== 'undefined' && indexedCreated[tmpAddress.pubkey] === address
)
) {
if (tmpAmount.indexOf('-') === -1) {
addressTo = tmpAddress.pubkey
addressAmount = tmpAmount
addressAmountPlus = true
} else {
addressFrom = tmpAddress.pubkey
addressAmount = tmpAmount.replace('-', '')
}
} else {
if (tmpAddress.signer) {
anyFromAddress = tmpAddress.pubkey
} else {
anyToAddress = tmpAddress.pubkey
}
}
}

if (!addressFrom && anySigner !== addressTo) {
addressFrom = anySigner
}
if (!addressFrom && !addressTo) {
return false
}
if (anyFromAddress && !addressFrom) {
addressFrom = anyFromAddress
}
if (anyToAddress && !addressTo) {
addressTo = anyToAddress
}
if (!addressTo) {
addressTo = 'System'
}

let formattedTime = transaction.blockTime
try {
Expand Down Expand Up @@ -194,7 +318,7 @@ export default class SolScannerProcessor {
const blockConfirmations = CACHE_LAST_BLOCK > 0 ? Math.round(CACHE_LAST_BLOCK - additional.slot * 1) : 0
const tx = {
transactionHash: transaction.signature,
blockHash: additional?.transaction?.message?.recentBlockhash,
blockHash: additional.transaction.message.recentBlockhash,
blockNumber: transaction.slot,
blockTime: formattedTime,
blockConfirmations,
Expand All @@ -203,7 +327,7 @@ export default class SolScannerProcessor {
addressTo: addressTo === address ? '' : addressTo,
addressAmount,
transactionStatus,
transactionFee: additional?.meta.fee
transactionFee: additional.meta.fee
}
if (typeof transaction.memo !== 'undefined' && transaction.memo) {
tx.transactionJson = { memo: transaction.memo }
Expand Down

0 comments on commit 24f3fe4

Please sign in to comment.