Skip to content

Commit

Permalink
Refactored TokenTrader
Browse files Browse the repository at this point in the history
  • Loading branch information
macterra committed Oct 21, 2023
1 parent 400aa5f commit 5065c41
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 59 deletions.
95 changes: 56 additions & 39 deletions frontend/src/TokenTrader.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ import {
Button,
Modal,
} from '@mui/material';
import axios from 'axios';
import InvoiceView from './InvoiceView';

const TokenTrader = ({ metadata, setRefreshKey }) => {
const [nfts, setNfts] = useState(0);
const [exchangeRate, setExchangeRate] = useState(null);
const [charge, setCharge] = useState(null);
const [modalOpen, setModalOpen] = useState(false);
const [invoiceUrl, setInvoiceUrl] = useState('');
const [nftSale, setNftSale] = useState(null);
const [invoice, setInvoice] = useState(null);
const [disableBuy, setDisableBuy] = useState(false);

useEffect(() => {
const fetchProfile = async () => {
Expand Down Expand Up @@ -130,7 +132,7 @@ const TokenTrader = ({ metadata, setRefreshKey }) => {
onClick={() => {
handleBuyClick(nft);
}}
disabled={!listed}
disabled={!listed || disableBuy}
>
Buy
</Button>
Expand All @@ -144,21 +146,24 @@ const TokenTrader = ({ metadata, setRefreshKey }) => {

const handleBuyClick = async (nft) => {
setNftSale(nft);
setDisableBuy(true);

try {
const response = await fetch('/api/v1/charge', {
method: 'POST',
headers: { 'Content-Type': 'application/json', },
body: JSON.stringify({ description: 'buy NFT', amount: nft.nft.price }),
const response = await axios.post('/api/v1/invoice', {
description: `buy ${nft.asset.title}`,
amount: nft.nft.price
});

const chargeData = await response.json();
const invoice = response.data;

if (chargeData.url) {
setCharge(chargeData);
setInvoiceUrl(chargeData.url);
if (invoice) {
setInvoice(invoice);
setModalOpen(true);
}
else {
setDisableBuy(false);
setNftSale(null);
}
} catch (error) {
console.error('Error:', error);
}
Expand All @@ -167,15 +172,12 @@ const TokenTrader = ({ metadata, setRefreshKey }) => {
const handleInvoiceClose = async () => {
setModalOpen(false);

try {
const response = await fetch(`/api/v1/charge/${charge.id}`);
const chargeData = await response.json();

if (chargeData.paid) {
if (invoice.paid) {
try {
const response = await fetch(`/api/v1/asset/${nftSale.xid}/buy`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', },
body: JSON.stringify({ price: nftSale.nft.price, chargeId: charge.id }),
body: JSON.stringify({ invoice: invoice }),
});

if (response.ok) {
Expand All @@ -185,10 +187,12 @@ const TokenTrader = ({ metadata, setRefreshKey }) => {
console.error('Error:', data.message);
alert(data.message);
}
} catch (error) {
console.error('Error:', error);
}
} catch (error) {
console.error('Error:', error);
}

setDisableBuy(false);
};

return (
Expand Down Expand Up @@ -233,26 +237,39 @@ const TokenTrader = ({ metadata, setRefreshKey }) => {
</TableBody>
</Table>
</TableContainer>
<Modal
open={modalOpen}
onClose={() => handleInvoiceClose()}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<div style={{ backgroundColor: '#282c34', padding: '1em', width: '50vw', height: '100vh', overflow: 'auto' }}>
<iframe
src={invoiceUrl}
title="Invoice"
width="100%"
height="90%"
style={{ border: 'none' }}
/>
<Button onClick={() => handleInvoiceClose()}>Close</Button>
</div>
</Modal>
{invoice &&
<Modal
open={modalOpen}
onClose={() => handleInvoiceClose()}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<div style={{
backgroundColor: '#282c34',
padding: '1em',
width: '600px',
height: '600px',
overflow: 'auto',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
}}>
<InvoiceView invoice={invoice} />
<Button
style={{ marginTop: '20px' }}
variant="contained"
color="primary"
onClick={() => handleInvoiceClose()}
>
Close
</Button>
</div>
</Modal>
}
</>
);
};
Expand Down
24 changes: 6 additions & 18 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -593,9 +593,8 @@ app.post('/api/v1/asset/:xid/buy', ensureAuthenticated, async (req, res) => {
try {
const xid = req.params.xid;
const buyerId = req.user.xid;
const { chargeId } = req.body;
const { invoice } = req.body;
const assetData = xidb.getAsset(xid);
const sellerId = assetData.asset.owner;

if (!assetData.nft) {
return res.status(500).json({ message: 'Error' });
Expand All @@ -605,24 +604,13 @@ app.post('/api/v1/asset/:xid/buy', ensureAuthenticated, async (req, res) => {
return res.status(500).json({ message: "Already owned" });
}

// TBD associate this charge with this asset for validation
const chargeData = await lnbits.checkCharge(chargeId);
const purchase = await xidb.purchaseAsset(xid, buyerId, invoice);

if (!chargeData.paid) {
console.log(`charge ${chargeId} not paid`);
return res.status(500).json({ message: 'Error' });
if (purchase.ok) {
xidb.commitChanges(purchase.message);
}

const price = chargeData.amount;

if (price != assetData.nft.price) {
console.log(`price mismatch between charge ${price} and nft ${assetData.nft.price}`);
return res.status(500).json({ message: 'Error' });
}

await xidb.purchaseAsset(xid, buyerId, chargeData);
xidb.commitChanges(`Purchase: ${sellerId} sold ${xid} to ${buyerId} for ${price} sats`);
res.json({ ok: true, message: 'Success' });

res.json(purchase);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ message: 'Error' });
Expand Down
17 changes: 15 additions & 2 deletions xidb.js
Original file line number Diff line number Diff line change
Expand Up @@ -1310,13 +1310,24 @@ const transferAsset = (xid, nextOwnerId) => {
saveNft(xid);
};

const purchaseAsset = async (xid, buyerId, chargeData) => {
const purchaseAsset = async (xid, buyerId, invoice) => {
const assetData = getAsset(xid);
const buyer = getAgent(buyerId);
const sellerId = assetData.asset.owner;
const seller = getAgent(sellerId);
const price = assetData.nft.price;

assert.ok(assetData.nft);
assert.ok(invoice.payment_hash);

const payment = await lnbits.checkPayment(invoice.payment_hash);

if (!payment || !payment.paid) {
return { ok: false, message: 'invoice not paid' };
}

invoice.payment = payment;

transferAsset(xid, buyerId);

const tokenData = getAsset(assetData.nft.asset);
Expand All @@ -1326,7 +1337,7 @@ const purchaseAsset = async (xid, buyerId, chargeData) => {
let audit = {
type: "sale",
agent: buyerId,
charge: chargeData,
invoice: invoice,
};

const royaltyRate = tokenData.token?.royalty || 0;
Expand Down Expand Up @@ -1464,6 +1475,8 @@ const purchaseAsset = async (xid, buyerId, chargeData) => {
}

saveAuditLog(audit);

return { ok: true, message: `Purchase: ${sellerId} sold ${xid} to ${buyerId} for ${price} sats` };
};

const pinAsset = async (xid) => {
Expand Down

0 comments on commit 5065c41

Please sign in to comment.