You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RTL/src/app/eclair/store/ecl.reducers.ts

303 lines
13 KiB
TypeScript

import { createReducer, on } from '@ngrx/store';
import { initECLState } from './ecl.state';
import { addInvoice, removeChannel, removePeer, resetECLStore, setActiveChannels, setChannelsStatus, setChildNodeSettingsECL, setFees, setInactiveChannels, setInfo, setInvoices, setLightningBalance, setOnchainBalance, setPayments, setPeers, setPendingChannels, setTransactions, updateECLAPICallStatus, updateChannelState, updateInvoice, updateRelayedPayment } from './ecl.actions';
import { Channel, PaymentReceived, PaymentRelayed } from '../../shared/models/eclModels';
export const ECLReducer = createReducer(initECLState,
on(updateECLAPICallStatus, (state, { payload }) => {
const updatedApisCallStatus = JSON.parse(JSON.stringify(state.apisCallStatus));
updatedApisCallStatus[payload.action || 0] = {
status: payload.status,
statusCode: payload.statusCode,
message: payload.message,
URL: payload.URL,
filePath: payload.filePath
};
return {
...state,
apisCallStatus: updatedApisCallStatus
};
}),
on(setChildNodeSettingsECL, (state, { payload }) => ({
...state,
nodeSettings: payload
})),
on(resetECLStore, (state, { payload }) => ({
...initECLState,
nodeSettings: payload
})),
on(setInfo, (state, { payload }) => ({
...state,
information: payload
})),
on(setFees, (state, { payload }) => ({
...state,
fees: payload
})),
on(setActiveChannels, (state, { payload }) => ({
...state,
activeChannels: payload
})),
on(setPendingChannels, (state, { payload }) => ({
...state,
pendingChannels: payload
})),
on(setInactiveChannels, (state, { payload }) => ({
...state,
inactiveChannels: payload
})),
on(setChannelsStatus, (state, { payload }) => ({
...state,
channelsStatus: payload
})),
on(setOnchainBalance, (state, { payload }) => ({
...state,
onchainBalance: payload
})),
on(setLightningBalance, (state, { payload }) => ({
...state,
lightningBalance: payload
})),
on(setPeers, (state, { payload }) => ({
...state,
peers: payload
})),
on(removePeer, (state, { payload }) => {
const modifiedPeers = [...state.peers];
const removePeerIdx = state.peers.findIndex((peer) => peer.nodeId === payload.nodeId);
if (removePeerIdx > -1) {
modifiedPeers.splice(removePeerIdx, 1);
}
return {
...state,
peers: modifiedPeers
};
}),
on(removeChannel, (state, { payload }) => {
const modifiedChannels = [...state.activeChannels];
const removeChannelIdx = state.activeChannels.findIndex((channel) => channel.channelId === payload.channelId);
if (removeChannelIdx > -1) {
modifiedChannels.splice(removeChannelIdx, 1);
}
return {
...state,
activeChannels: modifiedChannels
};
}),
on(setPayments, (state, { payload }) => {
if (payload && payload.sent) {
const storedChannels = [...state.activeChannels, ...state.pendingChannels, ...state.inactiveChannels];
payload.sent?.map((sentPayment) => {
const peerFound = state.peers.find((peer) => peer.nodeId === sentPayment.recipientNodeId);
sentPayment.recipientNodeAlias = peerFound ? peerFound.alias : sentPayment.recipientNodeId;
if (sentPayment.parts) {
sentPayment.parts?.map((part) => {
const channelFound = storedChannels.find((channel) => channel.channelId === part.toChannelId);
part.toChannelAlias = channelFound ? channelFound.alias : part.toChannelId;
return sentPayment.parts;
});
}
return payload.sent;
});
}
if (payload && payload.relayed) {
const storedChannels = [...state.activeChannels, ...state.pendingChannels, ...state.inactiveChannels];
payload.relayed.forEach((rlEvent) => {
rlEvent = mapAliases(rlEvent, storedChannels);
});
}
return {
...state,
payments: payload
};
}),
on(setTransactions, (state, { payload }) => ({
...state,
transactions: payload
})),
on(addInvoice, (state, { payload }) => {
const newInvoices = state.invoices;
newInvoices?.unshift(payload);
return {
...state,
invoices: newInvoices
};
}),
on(setInvoices, (state, { payload }) => ({
...state,
invoices: payload
})),
on(updateInvoice, (state, { payload }) => {
let modifiedInvoices = state.invoices;
modifiedInvoices = modifiedInvoices?.map((invoice) => {
if (invoice.paymentHash === payload.paymentHash) {
if (payload.hasOwnProperty('type')) {
const updatedInvoice = JSON.parse(JSON.stringify(invoice));
updatedInvoice.amountSettled = ((<PaymentReceived>payload).parts && (<PaymentReceived>payload).parts.length && (<PaymentReceived>payload).parts.length > 0 && (<PaymentReceived>payload).parts[0].amount) ? ((<PaymentReceived>payload).parts[0].amount || 0) / 1000 : 0;
updatedInvoice.receivedAt = ((<PaymentReceived>payload).parts && (<PaymentReceived>payload).parts.length && (<PaymentReceived>payload).parts.length > 0 && (<PaymentReceived>payload).parts[0].timestamp) ? Math.round(((<PaymentReceived>payload).parts[0].timestamp || 0) / 1000) : 0;
updatedInvoice.status = 'received';
return updatedInvoice;
} else {
return payload;
}
}
return invoice;
});
return {
...state,
invoices: modifiedInvoices
};
}),
on(updateChannelState, (state, { payload }) => {
let modifiedPendingChannels = state.pendingChannels;
modifiedPendingChannels = modifiedPendingChannels?.map((pendingChannel) => {
if (pendingChannel.channelId === payload.channelId && pendingChannel.nodeId === payload.remoteNodeId) {
payload.currentState = payload.currentState?.replace(/_/g, ' ');
pendingChannel.state = payload.currentState;
}
return pendingChannel;
});
return {
...state,
pendingChannels: modifiedPendingChannels
};
}),
on(updateRelayedPayment, (state, { payload }) => {
const modifiedPayments = state.payments;
const updatedPayload = mapAliases(payload, [...state.activeChannels, ...state.pendingChannels, ...state.inactiveChannels]);
updatedPayload.amountIn = Math.round((payload.amountIn || 0) / 1000);
updatedPayload.amountOut = Math.round((payload.amountOut || 0) / 1000);
modifiedPayments.relayed?.unshift(updatedPayload);
const feeSats = (payload.amountIn ||0) - (payload.amountOut || 0);
const modifiedLightningBalance = { localBalance: (state.lightningBalance.localBalance + feeSats), remoteBalance: (state.lightningBalance.remoteBalance - feeSats) };
const modifiedChannelStatus = state.channelsStatus;
if (modifiedChannelStatus.active) {
modifiedChannelStatus.active.capacity = (state.channelsStatus?.active?.capacity || 0) + feeSats;
}
const modifiedFees = {
daily_fee: ((state.fees.daily_fee || 0) + feeSats), daily_txs: ((state.fees.daily_txs || 0) + 1),
weekly_fee: ((state.fees.weekly_fee || 0) + feeSats), weekly_txs: ((state.fees.weekly_txs || 0) + 1),
monthly_fee: ((state.fees.monthly_fee || 0) + feeSats), monthly_txs: ((state.fees.monthly_txs || 0) + 1)
};
const modifiedActiveChannels = state.activeChannels;
let foundFrom = false;
let foundTo = false;
for (const channel of modifiedActiveChannels) {
if (channel.channelId === payload.fromChannelId) {
foundFrom = true;
const channelTotal = (channel.toLocal || 0) + (channel.toRemote || 0);
channel.toLocal = (channel.toLocal || 0) + updatedPayload.amountIn;
channel.toRemote = (channel.toRemote || 0) - updatedPayload.amountIn;
channel.balancedness = (channelTotal === 0) ? 1 : +(1 - Math.abs((channel.toLocal - channel.toRemote) / channelTotal)).toFixed(3);
}
if (channel.channelId === payload.toChannelId) {
foundTo = true;
const channelTotal = (channel.toLocal || 0) + (channel.toRemote || 0);
channel.toLocal = (channel.toLocal || 0) - updatedPayload.amountOut;
channel.toRemote = (channel.toRemote || 0) + updatedPayload.amountOut;
channel.balancedness = (channelTotal === 0) ? 1 : +(1 - Math.abs((channel.toLocal - channel.toRemote) / channelTotal)).toFixed(3);
}
if (foundTo && foundFrom) {
break;
}
};
return {
...state,
payments: modifiedPayments,
lightningBalance: modifiedLightningBalance,
channelStatus: modifiedChannelStatus,
fees: modifiedFees,
activeChannels: modifiedActiveChannels
};
})
);
const mapAliases = (rlEvent: PaymentRelayed, storedChannels: Channel[]) => {
if (rlEvent.type === 'payment-relayed') {
if (storedChannels && storedChannels.length > 0) {
for (let idx = 0; idx < storedChannels.length; idx++) {
if (storedChannels[idx].channelId?.toString() === rlEvent.fromChannelId) {
rlEvent.fromChannelAlias = storedChannels[idx].alias ? storedChannels[idx].alias : rlEvent.fromChannelId;
rlEvent.fromShortChannelId = storedChannels[idx].shortChannelId ? storedChannels[idx].shortChannelId : '';
if (rlEvent.toChannelAlias) {
return rlEvent;
}
}
if (storedChannels[idx].channelId?.toString() === rlEvent.toChannelId) {
rlEvent.toChannelAlias = storedChannels[idx].alias ? storedChannels[idx].alias : rlEvent.toChannelId;
rlEvent.toShortChannelId = storedChannels[idx].shortChannelId ? storedChannels[idx].shortChannelId : '';
if (rlEvent.fromChannelAlias) {
return rlEvent;
}
}
if (idx === storedChannels.length - 1) {
if (!rlEvent.fromChannelAlias) {
rlEvent.fromChannelAlias = rlEvent.fromChannelId?.substring(0, 17) + '...';
rlEvent.fromShortChannelId = '';
}
if (!rlEvent.toChannelAlias) {
rlEvent.toChannelAlias = rlEvent.toChannelId?.substring(0, 17) + '...';
rlEvent.toShortChannelId = '';
}
}
}
} else {
rlEvent.fromChannelAlias = rlEvent.fromChannelId?.substring(0, 17) + '...';
rlEvent.fromShortChannelId = '';
rlEvent.toChannelAlias = rlEvent.toChannelId?.substring(0, 17) + '...';
rlEvent.toShortChannelId = '';
}
} else if (rlEvent.type = 'trampoline-payment-relayed') {
if (storedChannels && storedChannels.length > 0) {
for (let idx = 0; idx < storedChannels.length; idx++) {
rlEvent.incoming?.forEach((incomingEvent) => {
if (storedChannels[idx].channelId?.toString() === incomingEvent.channelId) {
incomingEvent.channelAlias = storedChannels[idx].alias ? storedChannels[idx].alias : incomingEvent.channelId;
incomingEvent.shortChannelId = storedChannels[idx].shortChannelId ? storedChannels[idx].shortChannelId : '';
}
});
rlEvent.outgoing?.forEach((outgoingEvent) => {
if (storedChannels[idx].channelId?.toString() === outgoingEvent.channelId) {
outgoingEvent.channelAlias = storedChannels[idx].alias ? storedChannels[idx].alias : outgoingEvent.channelId;
outgoingEvent.shortChannelId = storedChannels[idx].shortChannelId ? storedChannels[idx].shortChannelId : '';
}
});
if (idx === storedChannels.length - 1) {
if (rlEvent.incoming && rlEvent.incoming.length && rlEvent.incoming.length > 0 && !rlEvent.incoming[0].channelAlias) {
rlEvent.incoming?.forEach((incomingEvent) => {
incomingEvent.channelAlias = incomingEvent.channelId?.substring(0, 17) + '...';
incomingEvent.shortChannelId = '';
});
}
if (rlEvent.outgoing && rlEvent.outgoing.length && rlEvent.outgoing.length > 0 && !rlEvent.outgoing[0].channelAlias) {
rlEvent.outgoing?.forEach((outgoingEvent) => {
outgoingEvent.channelAlias = outgoingEvent.channelId?.substring(0, 17) + '...';
outgoingEvent.shortChannelId = '';
});
}
}
}
} else {
rlEvent.incoming?.forEach((incomingEvent) => {
incomingEvent.channelAlias = incomingEvent.channelId?.substring(0, 17) + '...';
incomingEvent.shortChannelId = '';
});
rlEvent.outgoing?.forEach((outgoingEvent) => {
outgoingEvent.channelAlias = outgoingEvent.channelId?.substring(0, 17) + '...';
outgoingEvent.shortChannelId = '';
});
}
rlEvent.amountIn = rlEvent.incoming?.reduce((acc, curr) => acc + curr.amount, 0);
rlEvent.fromChannelId = rlEvent.incoming && rlEvent.incoming.length ? rlEvent.incoming[0].channelId : '';
rlEvent.fromChannelAlias = rlEvent.incoming && rlEvent.incoming.length ? rlEvent.incoming[0].channelAlias : '';
rlEvent.fromShortChannelId = rlEvent.incoming && rlEvent.incoming.length ? rlEvent.incoming[0].shortChannelId : '';
rlEvent.amountOut = rlEvent.outgoing?.reduce((acc, curr) => acc + curr.amount, 0);
rlEvent.toChannelId = rlEvent.outgoing && rlEvent.outgoing.length ? rlEvent.outgoing[0].channelId : '';
rlEvent.toChannelAlias = rlEvent.outgoing && rlEvent.outgoing.length ? rlEvent.outgoing[0].channelAlias : '';
rlEvent.toShortChannelId = rlEvent.outgoing && rlEvent.outgoing.length ? rlEvent.outgoing[0].shortChannelId : '';
}
return rlEvent;
};