Skip to content

Commit

Permalink
feat(suite-native): solana local graph history movements
Browse files Browse the repository at this point in the history
  • Loading branch information
vytick committed Oct 25, 2024
1 parent 96159d2 commit f063c1c
Showing 1 changed file with 147 additions and 4 deletions.
151 changes: 147 additions & 4 deletions suite-common/graph/src/balanceHistoryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,152 @@ export const getAccountHistoryMovementItemETH = ({
};
};

export const getAccountHistoryMovementItemSOL = ({
transactions,
from,
to,
}: GetAccountHistoryMovementItemParams): AccountHistoryMovement => {
const summaryMap = new Map<BlockTime, AccountHistoryMovementItem>();
const allTokensSummaryMap = new Map<TokenAddress, typeof summaryMap>();

transactions.forEach(tx => {
const { blockTime } = tx;

if (
!blockTime ||
tx.solanaSpecific === undefined ||
tx.type === 'failed' ||
tx.solanaSpecific.status !== 'confirmed'
) {
return;
}

if ((from && blockTime < from) || (to && blockTime > to)) {
return;
}

const bh: AccountHistoryMovementItem = {
time: blockTime,
txs: 1,
received: new BigNumber(0),
sent: new BigNumber(0),
sentToSelf: new BigNumber(0),
};

let countSentToSelf = false;
const solTxData = tx.solanaSpecific;

if (tx.details.vout.length > 0) {
const bchainVout = tx.details.vout[0];
const value = new BigNumber(bchainVout.value || '0');

if (bchainVout.addresses && bchainVout.addresses.length > 0) {
const txAddrDesc = bchainVout.addresses[0];

if (tx.descriptor === txAddrDesc) {
// Check if address is in selfAddrDesc
bh.received = bh.received.plus(value);
}

if (tx.descriptor === txAddrDesc) {
countSentToSelf = true;
}
}
}

for (const bchainVin of tx.details.vin) {
if (bchainVin.addresses && bchainVin.addresses.length > 0) {
const txAddrDesc = bchainVin.addresses[0];
if (txAddrDesc === tx.descriptor) {
if (solTxData.status === 'confirmed') {
const value = new BigNumber(tx.details.vout[0]?.value || '0');
bh.sent = bh.sent.plus(value);

if (countSentToSelf && txAddrDesc === tx.descriptor) {
bh.sentToSelf = bh.sentToSelf.plus(value);
}
}

bh.sent = bh.sent.plus(tx.fee);
}
}
}

tx.tokens.forEach(token => {
// skip empty amounts
if (token.amount === '') {
return;
}

if (token.type === 'sent' || token.type === 'recv' || token.type === 'self') {
const tokenSummary: AccountHistoryMovementItem = {
time: blockTime,
txs: 1,
received: new BigNumber(0),
sent: new BigNumber(0),
sentToSelf: new BigNumber(0),
};

const amount = new BigNumber(token.amount).div(10 ** token.decimals);

if (token.type === 'sent') {
tokenSummary.sent = tokenSummary.sent.plus(amount);
} else if (token.type === 'recv') {
tokenSummary.received = tokenSummary.received.plus(amount);
} else if (token.type === 'self') {
tokenSummary.sentToSelf = tokenSummary.sentToSelf.plus(amount);
}

const tokenContractId = token.contract as TokenAddress;

if (!allTokensSummaryMap.has(tokenContractId)) {
allTokensSummaryMap.set(tokenContractId, new Map());
}

const tokenSummaryMap = allTokensSummaryMap.get(tokenContractId)!;
const existingBlockSummary = tokenSummaryMap.get(blockTime);

if (existingBlockSummary) {
existingBlockSummary.txs += 1;
existingBlockSummary.received = existingBlockSummary.received.plus(
tokenSummary.received,
);
existingBlockSummary.sent = existingBlockSummary.sent.plus(tokenSummary.sent);
existingBlockSummary.sentToSelf = existingBlockSummary.sentToSelf.plus(
tokenSummary.sentToSelf,
);
} else {
tokenSummaryMap.set(blockTime, tokenSummary);
}
}
});

if (summaryMap.has(blockTime)) {
const summary = summaryMap.get(blockTime)!;
summary.txs += 1;
summary.received = summary.received.plus(bh.received);
summary.sent = summary.sent.plus(bh.sent);
summary.sentToSelf = summary.sentToSelf.plus(bh.sentToSelf);
} else {
summaryMap.set(blockTime, bh);
}
});

const sortedTokensSummaries: Record<TokenAddress, AccountHistoryMovementItem[]> = {};
for (const [contract, tokenSummaryMap] of allTokensSummaryMap.entries()) {
const sortedTokenSummaries = Array.from(tokenSummaryMap.values()).sort(
(a, b) => a.time - b.time,
);
sortedTokensSummaries[contract] = sortedTokenSummaries;
}
const sortedSummaries = Array.from(summaryMap.values()).sort((a, b) => a.time - b.time);

return {
main: sortedSummaries,
tokens: sortedTokensSummaries,
};
};

export const getAccountHistoryMovementFromTransactions = ({
transactions,
coin,
Expand All @@ -327,10 +473,7 @@ export const getAccountHistoryMovementFromTransactions = ({
case 'bnb':
return getAccountHistoryMovementItemETH({ transactions, from, to });
case 'sol':
return {
main: [] as AccountHistoryMovementItem[],
tokens: {},
} as AccountHistoryMovement;
return getAccountHistoryMovementItemSOL({ transactions, from, to });
default:
coin satisfies never;
throw new Error(`getAccountHistoryMovementItem: Unsupported network ${coin}`);
Expand Down

0 comments on commit f063c1c

Please sign in to comment.