Replace host port with peer address object (#1002)

* Delete old offer with peer and sent payment with peer structs

* Use peer_address as field name for all structs

* Use peer address object in proto responses

* Update frontend to use new peer address struct

* Undo change to navigate to peer address page params

* Update frontend build
This commit is contained in:
Jonathan Zernik 2021-08-20 22:03:32 -07:00 committed by GitHub
parent 479cab034d
commit 4f2f6107fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 89 additions and 97 deletions

View file

@ -43,8 +43,8 @@ export default function BuyOfferDetailItem({
event.preventDefault();
goToPeerAddressPage(
history,
offer.getPeerHost(),
offer.getPeerPort(),
offer.getPeerAddress().getHost(),
offer.getPeerAddress().getPort(),
);
}
@ -78,13 +78,15 @@ export default function BuyOfferDetailItem({
function PeerInfoContent() {
console.log(offer);
const peerAddress = offer.getPeerHost() + ":" + offer.getPeerPort();
const peerAddress = offer.getPeerAddress();
const host = peerAddress.getHost();
const peerAddressText = peerAddress.getHost() + ":" + peerAddress.getPort();
return (
<Box>
<Typography
size="md"
>Peer: <Link href="#" onClick={onPeerClick}>
{peerAddress}
{peerAddressText}
</Link>
</Typography>
</Box>

View file

@ -119,8 +119,10 @@ export default function BuySqueakDialog({
return null;
};
const getPeerAddress = (offer) => {
return offer.getPeerHost() + ":" + offer.getPeerPort();
const getPeerAddressText = (offer) => {
const peerAddress = offer.getPeerAddress();
const host = peerAddress.getHost();
return peerAddress.getHost() + ":" + peerAddress.getPort();
}
// TODO: load offers using "onRendered" callback.
@ -165,7 +167,7 @@ export default function BuySqueakDialog({
>
{offers.map(offer =>
<MenuItem key={offer.getOfferId()} value={offer.getOfferId()}>
{getPeerAddress(offer)} ({offer.getPriceMsat() / 1000} sats)
{getPeerAddressText(offer)} ({offer.getPriceMsat() / 1000} sats)
</MenuItem>
)}
</Select>

View file

@ -45,19 +45,21 @@ export default function ReceivedPayment({
event.preventDefault();
goToPeerAddressPage(
history,
receivedPayment.getPeerHost(),
receivedPayment.getPeerPort(),
receivedPayment.getPeerAddress().getHost(),
receivedPayment.getPeerAddress().getPort(),
);
}
function PeerDisplay() {
const peerAddress = receivedPayment.getPeerHost() + ":" + receivedPayment.getPeerPort();
const peerAddress = receivedPayment.getPeerAddress();
const host = peerAddress.getHost();
const peerAddressText = peerAddress.getHost() + ":" + peerAddress.getPort();
return (
<Box>
<Typography
size="md"
>Peer: <Link href="#" onClick={onPeerClick}>
{peerAddress}
{peerAddressText}
</Link>
</Typography>
</Box>

View file

@ -49,8 +49,8 @@ export default function SentPayment({
event.preventDefault();
goToPeerAddressPage(
history,
sentPayment.getPeerHost(),
sentPayment.getPeerPort(),
sentPayment.getPeerAddress().getHost(),
sentPayment.getPeerAddress().getPort(),
);
}
@ -62,13 +62,15 @@ export default function SentPayment({
}
function PeerDisplay() {
const peerAddress = sentPayment.getPeerHost() + ":" + sentPayment.getPeerPort();
const peerAddress = sentPayment.getPeerAddress();
const host = peerAddress.getHost();
const peerAddressText = peerAddress.getHost() + ":" + peerAddress.getPort();
return (
<Box>
<Typography
size="md"
>Peer: <Link href="#" onClick={onPeerClick}>
{peerAddress}
{peerAddressText}
</Link>
</Typography>
</Box>

View file

@ -750,7 +750,7 @@ def test_connect_other_node(
five_minutes = datetime.timedelta(minutes=5)
assert received_payment_time > datetime.datetime.now() - five_minutes
assert received_payment_time < datetime.datetime.now()
assert len(received_payment.peer_host) > 4
assert len(received_payment.peer_address.host) > 4
# Subscribe to received payments starting from index zero
subscribe_received_payments_response = admin_stub.SubscribeReceivedPayments(

View file

@ -678,11 +678,8 @@ message OfferDisplayEntry {
/// The invoice expiry
int32 invoice_expiry = 8;
/// The host of the squeak peer
string peer_host = 9;
/// The port of the squeak peer
int32 peer_port = 10;
/// The address of the squeak peer
PeerAddress peer_address = 9;
}
message SyncSqueaksRequest {
@ -741,11 +738,8 @@ message SentPayment {
/// Time of payment
int64 time_s = 7;
/// The host of the squeak peer
string peer_host = 8;
/// The port of the squeak peer
int32 peer_port = 9;
/// The address of the squeak peer
PeerAddress peer_address = 8;
}
message SyncSqueakRequest {
@ -833,11 +827,8 @@ message ReceivedPayment {
/// Time of payment
int64 time_s = 5;
/// The host of the squeak peer
string peer_host = 6;
/// The port of the squeak peer
int32 peer_port = 7;
/// The address of the squeak peer
PeerAddress peer_address = 6;
}
message SubscribeReceivedPaymentsRequest {
@ -966,3 +957,12 @@ message DisconnectPeerReply {
message SubscribeConnectedPeersRequest {
}
message PeerAddress {
/// The host of the peer
string host = 1;
/// The port of the peer
int32 port = 2;
}

View file

@ -3,12 +3,13 @@ import logging
from proto import squeak_admin_pb2
from squeaknode.admin.profile_image_util import bytes_to_base64_string
from squeaknode.admin.profile_image_util import load_default_profile_image
from squeaknode.core.received_offer_with_peer import ReceivedOffer
from squeaknode.core.peer_address import PeerAddress
from squeaknode.core.received_offer import ReceivedOffer
from squeaknode.core.received_payment import ReceivedPayment
from squeaknode.core.received_payment_summary import ReceivedPaymentSummary
from squeaknode.core.sent_offer import SentOffer
from squeaknode.core.sent_payment import SentPayment
from squeaknode.core.sent_payment_summary import SentPaymentSummary
from squeaknode.core.sent_payment_with_peer import SentPayment
from squeaknode.core.squeak_entry_with_profile import SqueakEntryWithProfile
from squeaknode.core.squeak_peer import SqueakPeer
from squeaknode.core.squeak_profile import SqueakProfile
@ -95,8 +96,7 @@ def offer_entry_to_message(received_offer: ReceivedOffer) -> squeak_admin_pb2.Of
node_port=received_offer.lightning_address.port,
invoice_timestamp=received_offer.invoice_timestamp,
invoice_expiry=received_offer.invoice_expiry,
peer_host=received_offer.peer_address.host,
peer_port=received_offer.peer_address.port,
peer_address=peer_address_to_message(received_offer.peer_address)
)
@ -113,8 +113,7 @@ def sent_payment_to_message(sent_payment: SentPayment) -> squeak_admin_pb2.SentP
node_pubkey=sent_payment.node_pubkey,
valid=sent_payment.valid,
time_s=int(sent_payment.created.timestamp()),
peer_host=sent_payment.peer_address.host,
peer_port=sent_payment.peer_address.port,
peer_address=peer_address_to_message(sent_payment.peer_address)
)
@ -149,8 +148,7 @@ def received_payments_to_message(received_payment: ReceivedPayment) -> squeak_ad
payment_hash=received_payment.payment_hash.hex(),
price_msat=received_payment.price_msat,
time_s=int(received_payment.created.timestamp()),
peer_host=received_payment.client_addr.host,
peer_port=received_payment.client_addr.port,
peer_address=peer_address_to_message(received_payment.peer_address)
)
@ -174,3 +172,10 @@ def connected_peer_to_message(connected_peer: Peer) -> squeak_admin_pb2.Connecte
port=connected_peer.port,
connect_time_s=connected_peer.connect_time,
)
def peer_address_to_message(peer_address: PeerAddress) -> squeak_admin_pb2.PeerAddress:
return squeak_admin_pb2.PeerAddress(
host=peer_address.host,
port=peer_address.port,
)

View file

@ -1,14 +1,14 @@
{
"files": {
"main.js": "/static/js/main.87eea864.chunk.js",
"main.js.map": "/static/js/main.87eea864.chunk.js.map",
"main.js": "/static/js/main.dd078910.chunk.js",
"main.js.map": "/static/js/main.dd078910.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.9f0ba400.js",
"runtime-main.js.map": "/static/js/runtime-main.9f0ba400.js.map",
"static/css/2.ea4ba2f0.chunk.css": "/static/css/2.ea4ba2f0.chunk.css",
"static/js/2.ec475cb5.chunk.js": "/static/js/2.ec475cb5.chunk.js",
"static/js/2.ec475cb5.chunk.js.map": "/static/js/2.ec475cb5.chunk.js.map",
"index.html": "/index.html",
"precache-manifest.b22e0ab54bd6f6290b7b2ea00074f545.js": "/precache-manifest.b22e0ab54bd6f6290b7b2ea00074f545.js",
"precache-manifest.a14377ec9407125fe4225bde0608031b.js": "/precache-manifest.a14377ec9407125fe4225bde0608031b.js",
"service-worker.js": "/service-worker.js",
"static/css/2.ea4ba2f0.chunk.css.map": "/static/css/2.ea4ba2f0.chunk.css.map",
"static/js/2.ec475cb5.chunk.js.LICENSE.txt": "/static/js/2.ec475cb5.chunk.js.LICENSE.txt",
@ -20,6 +20,6 @@
"static/js/runtime-main.9f0ba400.js",
"static/css/2.ea4ba2f0.chunk.css",
"static/js/2.ec475cb5.chunk.js",
"static/js/main.87eea864.chunk.js"
"static/js/main.dd078910.chunk.js"
]
}

View file

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Squeak Node</title><meta name="description" content="Squeak Node is a frontend for accessing a squeak node"><meta name="keywords" content="squeak, bitcoin, lightning"><meta name="author" content="Flatlogic LLC."><link href="/static/css/2.ea4ba2f0.chunk.css" rel="stylesheet"></head><body style="font-family:Roboto,sans-serif"><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,f,l=r[0],a=r[1],i=r[2],c=0,s=[];c<l.length;c++)f=l[c],Object.prototype.hasOwnProperty.call(o,f)&&o[f]&&s.push(o[f][0]),o[f]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var a=t[l];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={1:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)f.d(t,n,function(r){return e[r]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var l=this["webpackJsonpsqueak-node-frontend"]=this["webpackJsonpsqueak-node-frontend"]||[],a=l.push.bind(l);l.push=r,l=l.slice();for(var i=0;i<l.length;i++)r(l[i]);var p=a;t()}([])</script><script src="/static/js/2.ec475cb5.chunk.js"></script><script src="/static/js/main.87eea864.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Squeak Node</title><meta name="description" content="Squeak Node is a frontend for accessing a squeak node"><meta name="keywords" content="squeak, bitcoin, lightning"><meta name="author" content="Flatlogic LLC."><link href="/static/css/2.ea4ba2f0.chunk.css" rel="stylesheet"></head><body style="font-family:Roboto,sans-serif"><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,f,l=r[0],a=r[1],i=r[2],c=0,s=[];c<l.length;c++)f=l[c],Object.prototype.hasOwnProperty.call(o,f)&&o[f]&&s.push(o[f][0]),o[f]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var a=t[l];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={1:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)f.d(t,n,function(r){return e[r]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var l=this["webpackJsonpsqueak-node-frontend"]=this["webpackJsonpsqueak-node-frontend"]||[],a=l.push.bind(l);l.push=r,l=l.slice();for(var i=0;i<l.length;i++)r(l[i]);var p=a;t()}([])</script><script src="/static/js/2.ec475cb5.chunk.js"></script><script src="/static/js/main.dd078910.chunk.js"></script></body></html>

View file

@ -1,6 +1,6 @@
self.__precacheManifest = (self.__precacheManifest || []).concat([
{
"revision": "5070726c017f1f0b9b47ec403b539e2b",
"revision": "6c5cdfcab1c01b37639fdea4d28f88c9",
"url": "/index.html"
},
{
@ -16,8 +16,8 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "/static/js/2.ec475cb5.chunk.js.LICENSE.txt"
},
{
"revision": "1a5f7dafff302a293ecb",
"url": "/static/js/main.87eea864.chunk.js"
"revision": "c3ddd076bf622825d31c",
"url": "/static/js/main.dd078910.chunk.js"
},
{
"revision": "cc9816de5a8639d377ea",

View file

@ -14,7 +14,7 @@
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
importScripts(
"/precache-manifest.b22e0ab54bd6f6290b7b2ea00074f545.js"
"/precache-manifest.a14377ec9407125fe4225bde0608031b.js"
);
self.addEventListener('message', (event) => {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,11 +0,0 @@
from typing import NamedTuple
from typing import Optional
from squeaknode.core.received_offer import ReceivedOffer
from squeaknode.core.squeak_peer import SqueakPeer
class ReceivedOfferWithPeer(NamedTuple):
"""Class for saving an offer from a remote peer."""
received_offer: ReceivedOffer
peer: Optional[SqueakPeer]

View file

@ -13,4 +13,4 @@ class ReceivedPayment(NamedTuple):
payment_hash: bytes
price_msat: int
settle_index: int
client_addr: PeerAddress
peer_address: PeerAddress

View file

@ -15,4 +15,4 @@ class SentOffer(NamedTuple):
payment_request: str
invoice_time: int
invoice_expiry: int
client_addr: PeerAddress
peer_address: PeerAddress

View file

@ -1,10 +0,0 @@
from typing import NamedTuple
from typing import Optional
from squeaknode.core.sent_payment import SentPayment
from squeaknode.core.squeak_peer import SqueakPeer
class SentPaymentWithPeer(NamedTuple):
sent_payment: SentPayment
peer: Optional[SqueakPeer]

View file

@ -116,12 +116,12 @@ class SqueakCore:
block_info = self.bitcoin_client.get_best_block_info()
return block_info.block_height
def create_offer(self, squeak: CSqueak, client_address: PeerAddress, price_msat: int) -> SentOffer:
def create_offer(self, squeak: CSqueak, peer_address: PeerAddress, price_msat: int) -> SentOffer:
"""Creates an offer to sell a squeak key to another node.
Args:
squeak: The squeak to be sold.
client_address: The address of the buyer.
peer_address: The address of the buyer.
price_msat: The price in msats.
Returns:
@ -159,7 +159,7 @@ class SqueakCore:
payment_request=invoice_payment_request,
invoice_time=invoice_time,
invoice_expiry=invoice_expiry,
client_addr=client_address,
peer_address=peer_address,
)
def package_offer(self, sent_offer: SentOffer, lnd_external_host: str, lnd_port: int) -> Offer:
@ -314,7 +314,7 @@ class SqueakCore:
payment_hash=sent_offer.payment_hash,
price_msat=sent_offer.price_msat,
settle_index=settle_index,
client_addr=sent_offer.client_addr,
peer_address=sent_offer.peer_address,
)
except grpc.RpcError as e:
if e.code() != grpc.StatusCode.CANCELLED:

View file

@ -887,8 +887,8 @@ class SqueakDb:
payment_request=sent_offer.payment_request,
invoice_timestamp=sent_offer.invoice_time,
invoice_expiry=sent_offer.invoice_expiry,
client_host=sent_offer.client_addr.host,
client_port=sent_offer.client_addr.port,
client_host=sent_offer.peer_address.host,
client_port=sent_offer.peer_address.port,
)
with self.get_connection() as connection:
res = connection.execute(ins)
@ -919,7 +919,7 @@ class SqueakDb:
sent_offer = self._parse_sent_offer(row)
return sent_offer
def get_sent_offer_by_squeak_hash_and_client(self, squeak_hash: bytes, client_address: PeerAddress) -> Optional[SentOffer]:
def get_sent_offer_by_squeak_hash_and_client(self, squeak_hash: bytes, peer_address: PeerAddress) -> Optional[SentOffer]:
"""
Get a sent offer by squeak hash and client address host. Only
return sent offer if it's not expired and not paid.
@ -927,7 +927,7 @@ class SqueakDb:
s = (
select([self.sent_offers])
.where(self.sent_offers.c.squeak_hash == squeak_hash.hex())
.where(self.sent_offers.c.client_host == client_address.host)
.where(self.sent_offers.c.client_host == peer_address.host)
.where(self.sent_offer_is_not_paid)
.where(self.sent_offer_is_not_expired)
)
@ -988,8 +988,8 @@ class SqueakDb:
payment_hash=received_payment.payment_hash.hex(),
price_msat=received_payment.price_msat,
settle_index=received_payment.settle_index,
client_host=received_payment.client_addr.host,
client_port=received_payment.client_addr.port,
client_host=received_payment.peer_address.host,
client_port=received_payment.peer_address.port,
)
with self.get_connection() as connection:
try:
@ -1193,7 +1193,7 @@ class SqueakDb:
payment_request=row["payment_request"],
invoice_time=row["invoice_timestamp"],
invoice_expiry=row["invoice_expiry"],
client_addr=PeerAddress(
peer_address=PeerAddress(
host=row["client_host"],
port=row["client_port"],
),
@ -1207,7 +1207,7 @@ class SqueakDb:
payment_hash=bytes.fromhex(row["payment_hash"]),
price_msat=row["price_msat"],
settle_index=row["settle_index"],
client_addr=PeerAddress(
peer_address=PeerAddress(
host=row["client_host"],
port=row["client_port"],
),

View file

@ -122,7 +122,7 @@ class PeerMessageHandler:
if inv.type == 2:
offer = self.squeak_controller.get_buy_offer(
squeak_hash=inv.hash,
client_address=self.peer.peer_address,
peer_address=self.peer.peer_address,
)
if offer is None:
not_found.append(inv)

View file

@ -22,8 +22,8 @@ from squeaknode.core.peer_address import PeerAddress
from squeaknode.core.received_offer import ReceivedOffer
from squeaknode.core.received_payment_summary import ReceivedPaymentSummary
from squeaknode.core.sent_offer import SentOffer
from squeaknode.core.sent_payment import SentPayment
from squeaknode.core.sent_payment_summary import SentPaymentSummary
from squeaknode.core.sent_payment_with_peer import SentPaymentWithPeer
from squeaknode.core.squeak_entry_with_profile import SqueakEntryWithProfile
from squeaknode.core.squeak_peer import SqueakPeer
from squeaknode.core.squeak_profile import SqueakProfile
@ -95,27 +95,27 @@ class SqueakController:
followed_addresses = self.get_followed_addresses()
return set(followed_addresses) & set(addresses)
def get_buy_offer(self, squeak_hash: bytes, client_address: PeerAddress) -> Offer:
# Check if there is an existing offer for the hash/client_addr combination
sent_offer = self.get_saved_sent_offer(squeak_hash, client_address)
def get_buy_offer(self, squeak_hash: bytes, peer_address: PeerAddress) -> Offer:
# Check if there is an existing offer for the hash/peer_address combination
sent_offer = self.get_saved_sent_offer(squeak_hash, peer_address)
return self.squeak_core.package_offer(
sent_offer,
self.config.lnd.external_host,
self.config.lnd.port,
)
def get_saved_sent_offer(self, squeak_hash: bytes, client_address: PeerAddress) -> SentOffer:
# Check if there is an existing offer for the hash/client_addr combination
def get_saved_sent_offer(self, squeak_hash: bytes, peer_address: PeerAddress) -> SentOffer:
# Check if there is an existing offer for the hash/peer_address combination
sent_offer = self.squeak_db.get_sent_offer_by_squeak_hash_and_client(
squeak_hash,
client_address,
peer_address,
)
if sent_offer:
return sent_offer
squeak = self.get_squeak(squeak_hash)
sent_offer = self.squeak_core.create_offer(
squeak,
client_address,
peer_address,
self.config.core.price_msat,
)
self.squeak_db.insert_sent_offer(sent_offer)
@ -322,10 +322,10 @@ class SqueakController:
secret_key,
)
def get_sent_payments(self) -> List[SentPaymentWithPeer]:
def get_sent_payments(self) -> List[SentPayment]:
return self.squeak_db.get_sent_payments()
def get_sent_payment(self, sent_payment_id: int) -> Optional[SentPaymentWithPeer]:
def get_sent_payment(self, sent_payment_id: int) -> Optional[SentPayment]:
return self.squeak_db.get_sent_payment(sent_payment_id)
def get_sent_offers(self):