Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions OpenApi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,38 @@ components:
rsk:
type: string
type: object
SummaryData:
properties:
acceptedQuotesCount:
type: integer
lpEarnings:
$ref: '#/components/schemas/Wei'
paidQuotesAmount:
$ref: '#/components/schemas/Wei'
paidQuotesCount:
type: integer
refundedQuotesCount:
type: integer
totalAcceptedQuotedAmount:
$ref: '#/components/schemas/Wei'
totalFeesCollected:
$ref: '#/components/schemas/Wei'
totalPenaltyAmount:
$ref: '#/components/schemas/Wei'
totalQuotesCount:
type: integer
type: object
SummaryResult:
properties:
peginSummary:
$ref: '#/components/schemas/SummaryData'
type: object
pegoutSummary:
$ref: '#/components/schemas/SummaryData'
type: object
type: object
Wei: {}
entities.Wei: {}
pkg.AcceptQuoteRequest:
properties:
quoteHash:
Expand Down Expand Up @@ -1034,6 +1066,34 @@ paths:
"204":
description: ""
summary: Withdraw PegIn Collateral
/report/summaries:
get:
description: ' Returns financial data for a given period'
parameters:
- description: Start date in YYYY-MM-DD format
in: query
name: startDate
required: true
schema:
description: Start date in YYYY-MM-DD format
format: string
type: string
- description: End date in YYYY-MM-DD format
in: query
name: endDate
required: true
schema:
description: End date in YYYY-MM-DD format
format: string
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/SummaryResult'
description: Financial data for the given period
summary: Summaries
/reports/pegin:
get:
description: ' Get the last pegins on the API. Included in the management API.'
Expand Down
56 changes: 55 additions & 1 deletion internal/adapters/dataproviders/database/mongo/pegin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import (
"context"
"errors"
"fmt"
"time"

"github.com/rsksmart/liquidity-provider-server/internal/entities/quote"
"github.com/rsksmart/liquidity-provider-server/internal/usecases"
log "github.com/sirupsen/logrus"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"time"
"go.mongodb.org/mongo-driver/mongo/options"
)

const (
Expand Down Expand Up @@ -251,3 +253,55 @@ func (repo *peginMongoRepository) DeleteQuotes(ctx context.Context, quotes []str
}
return uint(peginResult.DeletedCount + retainedResult.DeletedCount + creationDataResult.DeletedCount), nil
}

func (repo *peginMongoRepository) ListQuotesByDateRange(ctx context.Context, startDate, endDate time.Time) ([]quote.PeginQuoteWithRetained, error) {
result := make([]quote.PeginQuoteWithRetained, 0)
dbCtx, cancel := context.WithTimeout(ctx, repo.conn.timeout)
defer cancel()
quoteFilter := bson.D{{Key: "agreement_timestamp", Value: bson.D{
{Key: "$gte", Value: startDate.Unix()},
{Key: "$lte", Value: endDate.Unix()},
}}}
findOpts := options.Find().SetSort(bson.D{{Key: "agreement_timestamp", Value: 1}})
quoteCursor, err := repo.conn.Collection(PeginQuoteCollection).Find(dbCtx, quoteFilter, findOpts)
if err != nil {
return nil, err
}
var storedQuotes []StoredPeginQuote
if err = quoteCursor.All(dbCtx, &storedQuotes); err != nil {
return nil, err
}
if len(storedQuotes) == 0 {
logDbInteraction(Read, result)
return result, nil
}
hashToIndex := make(map[string]int, len(storedQuotes))
quoteHashes := make([]string, len(storedQuotes))
result = make([]quote.PeginQuoteWithRetained, len(storedQuotes))
for i, stored := range storedQuotes {
quoteHashes[i] = stored.Hash
hashToIndex[stored.Hash] = i
result[i] = quote.PeginQuoteWithRetained{
Quote: stored.PeginQuote,
RetainedQuote: quote.RetainedPeginQuote{},
}
}
retainedCursor, err := repo.conn.Collection(RetainedPeginQuoteCollection).Find(
dbCtx,
bson.D{{Key: "quote_hash", Value: bson.D{{Key: "$in", Value: quoteHashes}}}},
)
if err != nil {
return result, err
}
var retainedQuotes []quote.RetainedPeginQuote
if err = retainedCursor.All(dbCtx, &retainedQuotes); err != nil {
return result, err
}
for _, retainedQuote := range retainedQuotes {
if idx, exists := hashToIndex[retainedQuote.QuoteHash]; exists {
result[idx].RetainedQuote = retainedQuote
}
}
logDbInteraction(Read, len(result))
return result, nil
}
57 changes: 55 additions & 2 deletions internal/adapters/dataproviders/database/mongo/pegout.go
Comment thread
Dominikkq marked this conversation as resolved.
Comment thread
Dominikkq marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import (
"context"
"errors"
"fmt"
"regexp"
"time"

"github.com/rsksmart/liquidity-provider-server/internal/entities/quote"
"github.com/rsksmart/liquidity-provider-server/internal/usecases"
log "github.com/sirupsen/logrus"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"regexp"
"time"
)

const (
Expand Down Expand Up @@ -360,3 +361,55 @@ func (repo *pegoutMongoRepository) UpsertPegoutDeposits(ctx context.Context, dep
}
return err
}

func (repo *pegoutMongoRepository) ListQuotesByDateRange(ctx context.Context, startDate, endDate time.Time) ([]quote.PegoutQuoteWithRetained, error) {
result := make([]quote.PegoutQuoteWithRetained, 0)
dbCtx, cancel := context.WithTimeout(ctx, repo.conn.timeout)
defer cancel()
quoteFilter := bson.D{{Key: "agreement_timestamp", Value: bson.D{
{Key: "$gte", Value: startDate.Unix()},
{Key: "$lte", Value: endDate.Unix()},
}}}
findOpts := options.Find().SetSort(bson.D{{Key: "agreement_timestamp", Value: 1}})
quoteCursor, err := repo.conn.Collection(PegoutQuoteCollection).Find(dbCtx, quoteFilter, findOpts)
if err != nil {
return nil, err
}
var storedQuotes []StoredPegoutQuote
if err = quoteCursor.All(dbCtx, &storedQuotes); err != nil {
return nil, err
}
if len(storedQuotes) == 0 {
logDbInteraction(Read, result)
return result, nil
}
hashToIndex := make(map[string]int, len(storedQuotes))
quoteHashes := make([]string, len(storedQuotes))
result = make([]quote.PegoutQuoteWithRetained, len(storedQuotes))
for i, stored := range storedQuotes {
quoteHashes[i] = stored.Hash
hashToIndex[stored.Hash] = i
result[i] = quote.PegoutQuoteWithRetained{
Quote: stored.PegoutQuote,
RetainedQuote: quote.RetainedPegoutQuote{},
}
}
retainedCursor, err := repo.conn.Collection(RetainedPegoutQuoteCollection).Find(
dbCtx,
bson.D{{Key: "quote_hash", Value: bson.D{{Key: "$in", Value: quoteHashes}}}},
)
if err != nil {
return result, err
}
var retainedQuotes []quote.RetainedPegoutQuote
if err = retainedCursor.All(dbCtx, &retainedQuotes); err != nil {
return result, err
}
for _, retainedQuote := range retainedQuotes {
if idx, exists := hashToIndex[retainedQuote.QuoteHash]; exists {
result[idx].RetainedQuote = retainedQuote
}
}
logDbInteraction(Read, len(result))
return result, nil
}
45 changes: 45 additions & 0 deletions internal/adapters/entrypoints/rest/assets/management.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,51 @@ <h5 class="card-title">Current Configuration</h5>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-md-12">
<div class="card">
<div class="card-header">Reports</div>
<div class="card-body">
<h5 class="card-title">Financial Summaries</h5>
<div class="row">
<div class="col-md-5">
<div class="mb-3">
<label for="summaryStartDate" class="form-label">Start Date</label>
<input type="date" class="form-control" id="summaryStartDate">
</div>
</div>
<div class="col-md-5">
<div class="mb-3">
<label for="summaryEndDate" class="form-label">End Date</label>
<input type="date" class="form-control" id="summaryEndDate">
</div>
</div>
<div class="col-md-2 d-flex align-items-end">
<div class="mb-3">
<button type="button" class="btn btn-primary" id="fetchSummariesButton">Generate Report</button>
</div>
</div>
</div>
<div id="summariesResult" style="display: none;">
<div class="row mt-3">
<div class="col-md-6">
<div class="card">
<div class="card-header">Pegin Summary</div>
<div class="card-body" id="peginSummary"></div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">Pegout Summary</div>
<div class="card-body" id="pegoutSummary"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

<div class="toast-container">
Expand Down
14 changes: 14 additions & 0 deletions internal/adapters/entrypoints/rest/assets/static/management.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,17 @@ pre {
50% { width: 50%; }
100% { width: 100%; }
}

#summariesResult {
margin-top: 20px;
}

#peginSummary table,
#pegoutSummary table {
margin-bottom: 0;
}

#peginSummary th,
#pegoutSummary th {
width: 60%;
}
64 changes: 64 additions & 0 deletions internal/adapters/entrypoints/rest/assets/static/management.js
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,62 @@ const addCollateral = async (amountId, endpoint, elementId, loadingBarId, button
}
};

const displaySummaryData = (container, data) => {
container.innerHTML = '';
const table = document.createElement('table');
table.classList.add('table', 'table-striped');
const rows = [
{ label: 'Total Quotes', value: data.totalQuotesCount },
{ label: 'Accepted Quotes', value: data.acceptedQuotesCount },
{ label: 'Paid Quotes', value: data.paidQuotesCount },
{ label: 'Paid Quotes Amount', value: data.paidQuotesAmount },
{ label: 'Total Accepted Amount', value: data.totalAcceptedQuotedAmount },
{ label: 'Total Fees Collected', value: data.totalFeesCollected },
{ label: 'Refunded Quotes', value: data.refundedQuotesCount },
{ label: 'Total Penalty Amount', value: data.totalPenaltyAmount },
{ label: 'LP Earnings', value: data.lpEarnings }
];
rows.forEach(row => {
const tr = document.createElement('tr');
const th = document.createElement('th');
th.textContent = row.label;
const td = document.createElement('td');
td.textContent = row.value;
tr.appendChild(th);
tr.appendChild(td);
table.appendChild(tr);
});
container.appendChild(table);
};

const fetchSummariesReport = async (csrfToken) => {
const startDate = document.getElementById('summaryStartDate').value;
const endDate = document.getElementById('summaryEndDate').value;
if (!startDate || !endDate) {
showErrorToast('Please select both start and end dates');
return;
}
try {
const response = await fetch(`/report/summaries?startDate=${startDate}&endDate=${endDate}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
}
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Failed to fetch summaries');
}
const data = await response.json();
document.getElementById('summariesResult').style.display = 'block';
displaySummaryData(document.getElementById('peginSummary'), data.peginSummary);
displaySummaryData(document.getElementById('pegoutSummary'), data.pegoutSummary);
} catch (error) {
showErrorToast(`Error fetching summaries: ${error.message}`);
}
};

document.addEventListener('DOMContentLoaded', () => {
const csrfToken = data.CsrfToken;
const configurations = data.Configuration;
Expand All @@ -582,6 +638,7 @@ document.addEventListener('DOMContentLoaded', () => {
document.getElementById('addPeginCollateralButton').addEventListener('click', () => addCollateral('addPeginCollateralAmount', '/pegin/addCollateral', 'peginCollateral', 'peginLoadingBar', 'addPeginCollateralButton', csrfToken));
document.getElementById('addPegoutCollateralButton').addEventListener('click', () => addCollateral('addPegoutCollateralAmount', '/pegout/addCollateral', 'pegoutCollateral', 'pegoutLoadingBar', 'addPegoutCollateralButton', csrfToken));
document.getElementById('saveConfig').addEventListener('click', () => saveConfig(csrfToken, configurations));
document.getElementById('fetchSummariesButton').addEventListener('click', () => fetchSummariesReport(csrfToken));

populateConfigSection('generalConfig', configurations.general);
populateConfigSection('peginConfig', configurations.pegin);
Expand All @@ -591,4 +648,11 @@ document.addEventListener('DOMContentLoaded', () => {
fetchData('/pegin/collateral', 'peginCollateral', csrfToken);
fetchData('/pegout/collateral', 'pegoutCollateral', csrfToken);
checkFeeWarnings();

const today = new Date();
const lastMonth = new Date(today);
lastMonth.setMonth(today.getMonth() - 1);

document.getElementById('summaryStartDate').value = lastMonth.toISOString().split('T')[0];
document.getElementById('summaryEndDate').value = today.toISOString().split('T')[0];
});
Loading
Loading