Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: lnp2pBot/bot
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.12.0
Choose a base ref
...
head repository: lnp2pBot/bot
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
  • 12 commits
  • 59 files changed
  • 3 contributors

Commits on Jan 6, 2025

  1. Remove image

    grunch committed Jan 6, 2025
    Copy the full SHA
    695a91b View commit details

Commits on Jan 23, 2025

  1. bot/modules/events: convert to TS (#625)

    Convert bot/modules/eventsmodule to TypeScript.
    webwarrior-ws authored Jan 23, 2025
    Copy the full SHA
    4a5d20b View commit details
  2. bot/modules/language: convert to TS (#626)

    Convert bot/modules/language to TypeScript.
    webwarrior-ws authored Jan 23, 2025
    Copy the full SHA
    67cf255 View commit details
  3. bot/modules/community: convert to TS (#623)

    Convert bot/modules/community module to TypeScript.
    webwarrior-ws authored Jan 23, 2025
    Copy the full SHA
    27d31b5 View commit details

Commits on Jan 29, 2025

  1. bot,util: fix "checkorder" command (#628)

    Don't raise an exception when seller or buyer is null in
    "checkorder" command code as this is a valid case (an order is
    in status pending).
    webwarrior-ws authored Jan 29, 2025
    Copy the full SHA
    819f8a1 View commit details

Commits on Feb 18, 2025

  1. Bump serialize-javascript and mocha (#636)

    Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) to 6.0.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.
    
    
    Updates `serialize-javascript` from 6.0.0 to 6.0.2
    - [Release notes](https://github.com/yahoo/serialize-javascript/releases)
    - [Commits](yahoo/serialize-javascript@v6.0.0...v6.0.2)
    
    Updates `mocha` from 9.2.2 to 11.1.0
    - [Release notes](https://github.com/mochajs/mocha/releases)
    - [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md)
    - [Commits](mochajs/mocha@v9.2.2...v11.1.0)
    
    ---
    updated-dependencies:
    - dependency-name: serialize-javascript
      dependency-type: indirect
    - dependency-name: mocha
      dependency-type: direct:development
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Feb 18, 2025
    Copy the full SHA
    ed45f64 View commit details
  2. Bump mongoose from 6.12.0 to 6.13.6 (#637)

    Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.12.0 to 6.13.6.
    - [Release notes](https://github.com/Automattic/mongoose/releases)
    - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
    - [Commits](Automattic/mongoose@6.12.0...6.13.6)
    
    ---
    updated-dependencies:
    - dependency-name: mongoose
      dependency-type: direct:production
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Feb 18, 2025
    Copy the full SHA
    034276b View commit details
  3. bot/modules/dispute: convert to TS (#624)

    * bot/modules/dispute: convert to TS
    
    Convert bot/modules/disputemodule to TypeScript.
    
    * bot/modules/dispute: fix bug in commands.ts
    
    Accidentally introduced when converting to TS
    (`order.previous_dispute_status` not set in `dispute`
    function).
    webwarrior-ws authored Feb 18, 2025
    Copy the full SHA
    a7f00f6 View commit details
  4. bot/modules/nostr: convert to TS (#627)

    * bot/modules/nostr: convert to TS
    
    Convert bot/modules/nostr to TypeScript.
    Specified "lib" property in tsconfig.json because otherwise
    TypeScript compiler complains about usage of `Promise.any`
    in bot/modules/nostr/index.ts:
    ```
    Property 'any' does not exist on type 'PromiseConstructor'. Do you need to change your target library? Try changing the lib compiler option to 'es2021' or later.
    ```
    
    * bot/modules/nostr: decode nostr sk from env. var
    
    Decode nostr secret key from environment variable using hex
    encoding. Also replace requires with imports.
    
    * bot/modules/nostr: move CommunityEvents import to top
    
    * bot/modules/nostr: fix imports
    
    Using `Nostr` from `nostr-tools` as before resulted in error:
    ```
    Cannot read properties of undefined (reading 'nip19') TypeError: Cannot read properties of undefined (reading 'nip19')
    ```
    webwarrior-ws authored Feb 18, 2025
    Copy the full SHA
    3e4ac23 View commit details
  5. bot/modules/user: convert to TS (#631)

    Convert bot/modules/user to TypeScript.
    webwarrior-ws authored Feb 18, 2025
    Copy the full SHA
    e8c973c View commit details

Commits on Feb 21, 2025

  1. bot/middleware: convert to TS (#632)

    Convert bot/middleware to TypeScript.
    webwarrior-ws authored Feb 21, 2025
    Copy the full SHA
    29a6f37 View commit details
  2. bot,models: convert bot to TS (#633)

    * bot,models: convert bot to TS
    
    Convert bot module (except bot/modules/orders) to TypeScript.
    
    Had to make several changes to IOrder model to allow some
    fields to have null or undefined value, as there is code that
    assigns these values.
    
    Also changed signature of several functions in bot/messages.ts
    so that `bot` argument now has `MainContext` type instead of
    `Telegraf<MainContext>`, because that's what gets passed by
    code that is calling those functions.
    
    * bot: introduced HasTelegram type
    
    Introduced HasTelegram type for use in functions that
    have `bot` argument, which can be either `Context` or
    `Telegraf<Context>`, but only `telegram` property is used.
    
    * bot/modules/orders: convert to TS
    
    Convert bot/modules/orders module to TypeScript.
    webwarrior-ws authored Feb 21, 2025
    Copy the full SHA
    22a0ec9 View commit details
Showing with 2,047 additions and 1,564 deletions.
  1. +80 −55 bot/{commands.js → commands.ts}
  2. 0 bot/{index.js → index.ts}
  3. +33 −33 bot/messages.ts
  4. +5 −3 bot/middleware/{commands.js → commands.ts}
  5. +0 −15 bot/middleware/index.js
  6. +11 −0 bot/middleware/index.ts
  7. +7 −6 bot/middleware/{stage.js → stage.ts}
  8. +6 −8 bot/middleware/{user.js → user.ts}
  9. +27 −14 bot/modules/community/{actions.js → actions.ts}
  10. +30 −28 bot/modules/community/{commands.js → commands.ts}
  11. +50 −0 bot/modules/community/communityContext.ts
  12. +9 −9 bot/modules/community/{index.js → index.ts}
  13. +27 −19 bot/modules/community/{messages.js → messages.ts}
  14. +13 −10 bot/modules/community/{scenes.communityAdmin.js → scenes.communityAdmin.ts}
  15. +127 −125 bot/modules/community/{scenes.js → scenes.ts}
  16. +17 −6 bot/modules/dispute/{actions.js → actions.ts}
  17. +36 −26 bot/modules/dispute/{commands.js → commands.ts}
  18. +5 −3 bot/modules/dispute/{index.js → index.ts}
  19. +27 −20 bot/modules/dispute/{messages.js → messages.ts}
  20. +0 −14 bot/modules/events/community.js
  21. +16 −0 bot/modules/events/community.ts
  22. +0 −16 bot/modules/events/index.js
  23. +26 −0 bot/modules/events/index.ts
  24. +0 −23 bot/modules/events/orders.js
  25. +24 −0 bot/modules/events/orders.ts
  26. +0 −13 bot/modules/language/actions.js
  27. +16 −0 bot/modules/language/actions.ts
  28. +0 −21 bot/modules/language/commands.js
  29. +23 −0 bot/modules/language/commands.ts
  30. +0 −8 bot/modules/language/index.js
  31. +10 −0 bot/modules/language/index.ts
  32. +4 −2 bot/modules/language/{messages.js → messages.ts}
  33. +6 −5 bot/modules/nostr/{commands.js → commands.ts}
  34. +0 −20 bot/modules/nostr/config.js
  35. +21 −0 bot/modules/nostr/config.ts
  36. +17 −8 bot/modules/nostr/{events.js → events.ts}
  37. +11 −8 bot/modules/nostr/{index.js → index.ts}
  38. +0 −11 bot/modules/nostr/lib.js
  39. +11 −0 bot/modules/nostr/lib.ts
  40. +51 −36 bot/modules/orders/{commands.js → commands.ts}
  41. +17 −22 bot/modules/orders/{index.js → index.ts}
  42. +12 −11 bot/modules/orders/{messages.js → messages.ts}
  43. +33 −33 bot/modules/orders/{scenes.js → scenes.ts}
  44. +13 −18 bot/modules/orders/{takeOrder.js → takeOrder.ts}
  45. +9 −3 bot/modules/user/{index.js → index.ts}
  46. +0 −1 bot/modules/user/scenes/index.js
  47. +3 −0 bot/modules/user/scenes/index.ts
  48. +46 −32 bot/modules/user/scenes/{settings.js → settings.ts}
  49. +67 −28 bot/{ordersActions.js → ordersActions.ts}
  50. +43 −25 bot/{scenes.js → scenes.ts}
  51. +6 −2 bot/start.ts
  52. +4 −4 bot/validations.ts
  53. BIN images/Icons8 Logo.png
  54. +2 −2 models/dispute.ts
  55. +6 −6 models/order.ts
  56. +1,036 −809 package-lock.json
  57. +2 −2 package.json
  58. +1 −0 tsconfig.json
  59. +1 −1 util/index.ts
135 changes: 80 additions & 55 deletions bot/commands.js → bot/commands.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
const {
validateFiatSentOrder,
validateReleaseOrder,
} = require('./validations');
import { validateFiatSentOrder, validateReleaseOrder } from './validations';
const {
createHoldInvoice,
subscribeInvoice,
cancelHoldInvoice,
settleHoldInvoice,
} = require('../ln');
const { Order, User, Dispute } = require('../models');
const messages = require('./messages');
const {
getBtcFiatPrice,
deleteOrderFromChannel,
getUserI18nContext,
getFee,
} = require('../util');
const ordersActions = require('./ordersActions');
import { Order, User, Dispute } from '../models';
import * as messages from './messages';
import { getBtcFiatPrice, deleteOrderFromChannel, getUserI18nContext, getFee } from '../util';
import * as ordersActions from './ordersActions';
const OrderEvents = require('./modules/events/orders');
const { removeLightningPrefix } = require('../util');

const { resolvLightningAddress } = require('../lnurl/lnurl-pay');
const { logger } = require('../logger');
import { resolvLightningAddress } from '../lnurl/lnurl-pay';
import { logger } from '../logger';
import { Telegraf } from 'telegraf';
import { IOrder } from '../models/order';
import { UserDocument } from '../models/user';
import { MainContext } from './start';
import { CommunityContext } from './modules/community/communityContext';
import { Types } from 'mongoose';

const waitPayment = async (ctx, bot, buyer, seller, order, buyerInvoice) => {
const waitPayment = async (ctx: MainContext, bot: MainContext, buyer: UserDocument, seller: UserDocument, order: IOrder, buyerInvoice: any) => {
try {
// If there is not fiat amount the function don't do anything
if (order.fiat_amount === undefined) {
@@ -64,13 +62,15 @@ const waitPayment = async (ctx, bot, buyer, seller, order, buyerInvoice) => {
});
order.hash = hash;
order.secret = secret;
order.taken_at = Date.now();
order.taken_at = new Date();
order.status = 'WAITING_PAYMENT';
// We monitor the invoice to know when the seller makes the payment
await subscribeInvoice(bot, hash);

// We pass the buyer for rate and age calculations
const buyer = await User.findById(order.buyer_id);
if(buyer === null)
throw new Error("buyer was not found");
// We send the hold invoice to the seller
await messages.invoicePaymentRequestMessage(
ctx,
@@ -88,12 +88,12 @@ const waitPayment = async (ctx, bot, buyer, seller, order, buyerInvoice) => {
}
};

const addInvoice = async (ctx, bot, order) => {
const addInvoice = async (ctx: CommunityContext, bot: MainContext, order: IOrder | null) => {
try {
ctx.deleteMessage();
ctx.scene.leave();
if (!order) {
const orderId = ctx.update.callback_query.message.text;
const orderId = (ctx.update as any).callback_query.message.text;
if (!orderId) return;
order = await Order.findOne({ _id: orderId });
if (!order) return;
@@ -105,6 +105,8 @@ const addInvoice = async (ctx, bot, order) => {
}

const buyer = await User.findOne({ _id: order.buyer_id });
if (buyer === null)
throw new Error("buyer was not found");

if (order.fiat_amount === undefined) {
ctx.scene.enter('ADD_FIAT_AMOUNT_WIZARD_SCENE_ID', {
@@ -115,9 +117,11 @@ const addInvoice = async (ctx, bot, order) => {
return;
}

let amount = order.amount;
let amount: number | undefined = order.amount;
if (amount === 0) {
amount = await getBtcFiatPrice(order.fiat_code, order.fiat_amount);
if(amount === undefined)
throw new Error("amount is undefined");
const marginPercent = order.price_margin / 100;
amount = amount - amount * marginPercent;
amount = Math.floor(amount);
@@ -132,6 +136,8 @@ const addInvoice = async (ctx, bot, order) => {
}
await order.save();
const seller = await User.findOne({ _id: order.seller_id });
if (seller === null)
throw new Error("seller was not found");

if (buyer.lightning_address) {
const laRes = await resolvLightningAddress(
@@ -171,21 +177,25 @@ const addInvoice = async (ctx, bot, order) => {
}
};

const rateUser = async (ctx, bot, rating, orderId) => {
const rateUser = async (ctx: CommunityContext, bot: MainContext, rating: number, orderId: string) => {
try {
ctx.deleteMessage();
ctx.scene.leave();
const callerId = ctx.from.id;
const callerId = ctx.from?.id;

if (!orderId) return;
const order = await Order.findOne({ _id: orderId });

if (!order) return;
if (order === null) return;
const buyer = await User.findOne({ _id: order.buyer_id });
if (buyer === null)
throw new Error("buyer was not found");
const seller = await User.findOne({ _id: order.seller_id });
if (seller === null)
throw new Error("seller was not found");

let targetUser = buyer;
if (callerId == buyer.tg_id) {
if (String(callerId) == buyer?.tg_id) {
targetUser = seller;
}

@@ -201,7 +211,7 @@ const rateUser = async (ctx, bot, rating, orderId) => {
}
};

const saveUserReview = async (targetUser, rating) => {
const saveUserReview = async (targetUser: UserDocument, rating: number) => {
try {
let totalReviews = targetUser.total_reviews
? targetUser.total_reviews
@@ -230,36 +240,38 @@ const saveUserReview = async (targetUser, rating) => {
}
};

const cancelAddInvoice = async (ctx, order, job) => {
const cancelAddInvoice = async (ctx: CommunityContext, order: IOrder | null, job?: any) => {
try {
let userAction = false;
let userTgId = false;
let userTgId = null;
if (!job) {
ctx.deleteMessage();
ctx.scene.leave();
userAction = true;
userTgId = ctx.from.id;
if (!order) {
const orderId = !!ctx && ctx.update.callback_query.message.text;
userTgId = String(ctx.from.id);
if (order === null) {
const orderId = !!ctx && (ctx.update as any).callback_query.message.text;
if (!orderId) return;
order = await Order.findOne({ _id: orderId });
if (!order) return;
}
}
if (order === null) return;

// We make sure the seller can't send us sats now
await cancelHoldInvoice({ hash: order.hash });

const user = await User.findOne({ _id: order.buyer_id });

if (!user) return;
if (user == null) return;

const i18nCtx = await getUserI18nContext(user);
// Buyers only can cancel orders with status WAITING_BUYER_INVOICE
if (order.status !== 'WAITING_BUYER_INVOICE')
return await messages.genericErrorMessage(ctx, user, i18nCtx);

const sellerUser = await User.findOne({ _id: order.seller_id });
if(sellerUser === null)
throw new Error("sellerUser was not found");
const buyerUser = await User.findOne({ _id: order.buyer_id });
const sellerTgId = sellerUser.tg_id;
// If order creator cancels it, it will not be republished
@@ -345,14 +357,14 @@ const cancelAddInvoice = async (ctx, order, job) => {
}
};

const showHoldInvoice = async (ctx, bot, order) => {
const showHoldInvoice = async (ctx: CommunityContext, bot: MainContext, order: IOrder | null) => {
try {
ctx.deleteMessage();
if (!order) {
const orderId = ctx.update.callback_query.message.text;
const orderId = (ctx.update as any).callback_query.message.text;
if (!orderId) return;
order = await Order.findOne({ _id: orderId });
if (!order) return;
if (order === null) return;
}

const user = await User.findOne({ _id: order.seller_id });
@@ -383,6 +395,8 @@ const showHoldInvoice = async (ctx, bot, order) => {
let amount;
if (order.amount === 0) {
amount = await getBtcFiatPrice(order.fiat_code, order.fiat_amount);
if(amount === undefined)
throw new Error("amount is undefined");
const marginPercent = order.price_margin / 100;
amount = amount - amount * marginPercent;
amount = Math.floor(amount);
@@ -413,22 +427,22 @@ const showHoldInvoice = async (ctx, bot, order) => {
}
};

const cancelShowHoldInvoice = async (ctx, order, job) => {
const cancelShowHoldInvoice = async (ctx: CommunityContext, order: IOrder | null, job?: any) => {
try {
let userAction = false;
let userTgId = false;
let userTgId = null;
if (!job) {
ctx.deleteMessage();
ctx.scene.leave();
userAction = true;
userTgId = ctx.from.id;
if (!order) {
const orderId = !!ctx && ctx.update.callback_query.message.text;
userTgId = String(ctx.from.id);
if (order === null) {
const orderId = !!ctx && (ctx.update as any).callback_query.message.text;
if (!orderId) return;
order = await Order.findOne({ _id: orderId });
if (!order) return;
}
}
if (order === null) return;

// We make sure the seller can't send us sats now
await cancelHoldInvoice({ hash: order.hash });
@@ -441,6 +455,8 @@ const cancelShowHoldInvoice = async (ctx, order, job) => {
return await messages.genericErrorMessage(ctx, user, i18nCtx);

const buyerUser = await User.findOne({ _id: order.buyer_id });
if(buyerUser === null)
throw new Error("buyerUser was not found");
const sellerUser = await User.findOne({ _id: order.seller_id });
const buyerTgId = buyerUser.tg_id;
// If order creator cancels it, it will not be republished
@@ -534,17 +550,19 @@ const cancelShowHoldInvoice = async (ctx, order, job) => {
* @param {*} order
* @returns
*/
const addInvoicePHI = async (ctx, bot, orderId) => {
const addInvoicePHI = async (ctx: CommunityContext, bot: MainContext, orderId: string) => {
try {
ctx.deleteMessage();
const order = await Order.findOne({ _id: orderId });
if (order === null)
throw new Error("order was not found");
// orders with status PAID_HOLD_INVOICE are released payments
if (order.status !== 'PAID_HOLD_INVOICE' && order.status !== 'FROZEN') {
return;
}

const buyer = await User.findOne({ _id: order.buyer_id });
if (!buyer) return;
if (buyer === null) return;
if (order.amount === 0) {
await messages.genericErrorMessage(bot, buyer, ctx.i18n);
return;
@@ -556,16 +574,16 @@ const addInvoicePHI = async (ctx, bot, orderId) => {
}
};

const cancelOrder = async (ctx, orderId, user) => {
const cancelOrder = async (ctx: CommunityContext, orderId: string, user: UserDocument | null) => {
try {
if (!user) {
const tgUser = ctx.update.callback_query.from;
if (user === null) {
const tgUser = (ctx.update as any).callback_query.from;
if (!tgUser) return;

user = await User.findOne({ tg_id: tgUser.id });

// If user didn't initialize the bot we can't do anything
if (!user) return;
if (user == null) return;
}
if (user.banned) return await messages.bannedUserErrorMessage(ctx, user);
const order = await ordersActions.getOrder(ctx, user, orderId);
@@ -623,18 +641,23 @@ const cancelOrder = async (ctx, orderId, user) => {
initiator = 'seller';
counterParty = 'buyer';
}
if (counterPartyUser == null)
throw new Error("counterPartyUser was not found");

if (order[`${initiator}_cooperativecancel`])
const initiatorCooperativeCancelProperty =
initiator == 'seller' ? 'seller_cooperativecancel' : 'buyer_cooperativecancel';

if (order[initiatorCooperativeCancelProperty])
return await messages.shouldWaitCooperativeCancelMessage(
ctx,
initiatorUser
);

order[`${initiator}_cooperativecancel`] = true;
order[initiatorCooperativeCancelProperty] = true;

const i18nCtxCP = await getUserI18nContext(counterPartyUser);
// If the counter party already requested a cooperative cancel order
if (order[`${counterParty}_cooperativecancel`]) {
if (counterParty == 'seller' ? order.seller_cooperativecancel : order.buyer_cooperativecancel) {
// If we already have a holdInvoice we cancel it and return the money
if (order.hash) await cancelHoldInvoice({ hash: order.hash });

@@ -677,10 +700,10 @@ const cancelOrder = async (ctx, orderId, user) => {
}
};

const fiatSent = async (ctx, orderId, user) => {
const fiatSent = async (ctx: MainContext, orderId: string, user: UserDocument | null) => {
try {
if (!user) {
const tgUser = ctx.update.callback_query.from;
const tgUser = (ctx.update as any).callback_query.from;
if (!tgUser) return;

user = await User.findOne({ tg_id: tgUser.id });
@@ -694,6 +717,8 @@ const fiatSent = async (ctx, orderId, user) => {

order.status = 'FIAT_SENT';
const seller = await User.findOne({ _id: order.seller_id });
if (seller === null)
throw new Error("seller was not found");
await order.save();
// We sent messages to both parties
// We need to create i18n context for each user
@@ -711,10 +736,10 @@ const fiatSent = async (ctx, orderId, user) => {
}
};

const release = async (ctx, orderId, user) => {
const release = async (ctx: MainContext, orderId: string, user: UserDocument | null) => {
try {
if (!user) {
const tgUser = ctx.update.callback_query.from;
const tgUser = (ctx.update as any).callback_query.from;
if (!tgUser) return;

user = await User.findOne({ tg_id: tgUser.id });
@@ -739,7 +764,7 @@ const release = async (ctx, orderId, user) => {
}
};

module.exports = {
export {
rateUser,
saveUserReview,
cancelAddInvoice,
File renamed without changes.
Loading