From d80f59bd3b8ad48e409b879500f394136898a4d7 Mon Sep 17 00:00:00 2001 From: Keith Irwin Date: Mon, 22 Apr 2024 23:08:35 -0600 Subject: [PATCH] feat: :construction: Built initial payment frontend --- docker-compose.yml | 3 ++ main.js | 48 +++++++++++++++++--- merch/index.html | 11 +++++ merch/style.css | 0 package-lock.json | 9 ++-- package.json | 6 ++- pay/index.html | 106 +++++++++++++++++++++++++++++++++++++++++++++ pay/style.css | 0 sample.env | 3 ++ wallet.dockerfile | 2 +- 10 files changed, 174 insertions(+), 14 deletions(-) create mode 100644 merch/index.html create mode 100644 merch/style.css create mode 100644 pay/index.html create mode 100644 pay/style.css diff --git a/docker-compose.yml b/docker-compose.yml index 0668e93..ca7df85 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,6 +50,7 @@ services: --rpc-bind-port=18082 --password ${WALLET_PASSWORD} --daemon-host=${MONERO_DAEMON_HOST} + --tx-notify "/usr/bin/curl -s http://pago_api/new_tx/%s" networks: monero: @@ -73,6 +74,8 @@ services: container_name: pago_api build: . restart: unless-stopped + depends_on: + - wallet command: start networks: monero: diff --git a/main.js b/main.js index d3025aa..b1fe671 100644 --- a/main.js +++ b/main.js @@ -1,6 +1,9 @@ const dotenv = require('dotenv') const express = require('express') +const cors = require('cors') const Wallet = require('monero-wallet-rpc-js') +const {createServer} = require('node:http') +const {Server} = require('socket.io') ;(async () => { @@ -61,7 +64,7 @@ const Wallet = require('monero-wallet-rpc-js') } return getAccount(i) } else { - console.log(`Account #${i} exists with a balance of ${deAtomize(account.balance)} XMR.`) + console.log(`Using account #${i} (balance: ${deAtomize(account.balance)} XMR).`) return account } }; getAccount(WALLET_ACCOUNT_INDEX) @@ -70,8 +73,20 @@ const Wallet = require('monero-wallet-rpc-js') // Server const app = express() app.use(express.json()) - app.listen(80) + app.use(cors({ + // origin: 'http://example.com', + })) + const server = createServer(app) + const io = new Server(server) + server.listen(80) + // Test websockets + io.on('connection', (socket) => { + console.log('a user connected') + socket.on('disconnect', () => { + console.log('user disconnected') + }) + }) // Healthchecks app.get('/wallet/height', async (req, res) => @@ -107,16 +122,16 @@ const Wallet = require('monero-wallet-rpc-js') // Check payment app.get('/payment/:addr', async (req, res) => { let subaddr_index; try { - subaddr_index = (await wallet.getAddressIndex({ - address: req.params.addr - })).index.minor + subaddr_index = (await wallet.getAddressIndex(req.params.addr)).index.minor } catch (err) { console.error(`Failed to get index of subaddress: ${err}`) - return res.status(500).sendText('Failed to determine subaddress index!') + return res.sendStatus(500) } let transfers; try { transfers = Object.values(await wallet.getTransfers({ + all_accounts: true, in: true, + out: false, pending: true, failed: true, pool: true, @@ -125,9 +140,28 @@ const Wallet = require('monero-wallet-rpc-js') })).flat() } catch (err) { console.error(`Failed to get transactions for subaddress: ${err}`) - return res.status(500).sendText('Failed to get transactions!') + return res.sendStatus(500) } return res.json(transfers) }) + // Listen for new transactions + app.get('/new_tx/:txid', async (req, res) => { + // TODO: Retry, sleep, retry, give up + console.log(`New transaction: ${req.params.txid}`) + let result; try { + result = await wallet.getTransfersByTxid({ + account_index: WALLET_ACCOUNT_INDEX, + txid: req.params.txid, + }) + if (result.transfer===undefined) throw new Error('Multiple transfers?') + } catch (err) { + console.error(`Failed to query transaction: ${err}`) + return res.sendStatus(500) + } + console.log(`Transfer received at ${result.transfer.subaddr_index.minor} for ${deAtomize(result.transfer.amount)} XMR to ${result.transfer.address}`) + // TODO: Send websocket + return res.sendStatus(200) + }) + })() diff --git a/merch/index.html b/merch/index.html new file mode 100644 index 0000000..93aa831 --- /dev/null +++ b/merch/index.html @@ -0,0 +1,11 @@ + + + Merchant Dashboard + + +

Merchant Dashboard

+

+ + + + diff --git a/merch/style.css b/merch/style.css new file mode 100644 index 0000000..e69de29 diff --git a/package-lock.json b/package-lock.json index c553197..3d4c50a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,10 @@ "version": "1.1.5", "license": "MIT", "dependencies": { + "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", - "monero-wallet-rpc-js": "^1.2.20", + "monero-wallet-rpc-js": "^1.2.22", "socket.io": "^4.7.5" } }, @@ -625,9 +626,9 @@ } }, "node_modules/monero-wallet-rpc-js": { - "version": "1.2.20", - "resolved": "https://registry.npmjs.org/monero-wallet-rpc-js/-/monero-wallet-rpc-js-1.2.20.tgz", - "integrity": "sha512-Hvdxvugs911QL6lte9SaauQLUfTT+ZXrAJ1W9DX5acczEqhSncuneN9bSFQnXgGKeIg37FU9dkVfFK3G1Rkl6g==", + "version": "1.2.22", + "resolved": "https://registry.npmjs.org/monero-wallet-rpc-js/-/monero-wallet-rpc-js-1.2.22.tgz", + "integrity": "sha512-egQES7wI7yK11YhuLhM6+qgA0350Zco7itdhfIpcl6y9ksaVcGqUZeH8889eplN6KX2V7oF+DiIMZkCAQnf6ZA==", "dependencies": { "axios": "^1.6.8" } diff --git a/package.json b/package.json index 6e82d1c..331e1ed 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "pago", - "version": "1.1.5", + "version": "1.2.0", "description": "Lightweight monero payment gateway", "main": "main.js", + "type": "commonjs", "scripts": { "start": "node main.js" }, @@ -16,9 +17,10 @@ "author": "Keith Irwin (www.ki9.us)", "license": "MIT", "dependencies": { + "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", - "monero-wallet-rpc-js": "^1.2.20", + "monero-wallet-rpc-js": "^1.2.22", "socket.io": "^4.7.5" } } diff --git a/pay/index.html b/pay/index.html new file mode 100644 index 0000000..9a2e6f8 --- /dev/null +++ b/pay/index.html @@ -0,0 +1,106 @@ + + + + Payment + + +

Payment

+ + + + + +

Transactions

+ + + + + + + + + + + + + + + + + +
DateTimeAmtConfsBlockStat
+ ⏲️ + + +
+ + + + + + + diff --git a/pay/style.css b/pay/style.css new file mode 100644 index 0000000..e69de29 diff --git a/sample.env b/sample.env index 6866b90..854b869 100644 --- a/sample.env +++ b/sample.env @@ -23,6 +23,9 @@ WALLET_VIEWKEY='a23474fe2d3ef001b7f0d311d7bb10eb149bbf9c0e206f7f31cc91ab58781809 WALLET_RESTORE_HEIGHT=3133069 # Which wallet account to use for payments WALLET_ACCOUNT_INDEX=1 +# "Recipient" name that payers will see in their wallet history +# Change this to the name of your organization +PAYMENT_RECIPIENT='Sample company (www.example.com)' # Wallet filename WALLET_FILENAME='pago' # Wallet RPC diff --git a/wallet.dockerfile b/wallet.dockerfile index 9e4992e..b249ae0 100644 --- a/wallet.dockerfile +++ b/wallet.dockerfile @@ -37,7 +37,7 @@ FROM ubuntu:20.04 RUN set -ex && \ apt-get update && \ - apt-get --no-install-recommends --yes install ca-certificates && \ + apt-get --no-install-recommends --yes install ca-certificates curl && \ apt-get clean && \ rm -rf /var/lib/apt COPY --from=builder /usr/local/src/monero/build/x86_64-linux-gnu/release/bin /usr/local/bin/