Skip to content

Add counterparty requirements customization#794

Open
Luquitasjeffrey wants to merge 6 commits intomainfrom
add-counterparty-requirements-customization
Open

Add counterparty requirements customization#794
Luquitasjeffrey wants to merge 6 commits intomainfrom
add-counterparty-requirements-customization

Conversation

@Luquitasjeffrey
Copy link
Copy Markdown
Collaborator

@Luquitasjeffrey Luquitasjeffrey commented May 2, 2026

Fixes #648
It adds a /requirements command to configure counteparty requirements for other users to take published orders.
Why someone would want to do this?
Suppose I want to trade some sats and I want the counterparty to be an experienced user, this filtering allows me to find a better counterpart and reduce the fraud risk, or the risk of wasting time with a counterparty that doesn't wants to trade.

Summary by CodeRabbit

  • New Features

    • Users can set counterparty requirements (minimum account age and minimum completed orders) via the new /requirements wizard, including commands to update or reset values.
    • Order-taking now enforces those counterparty requirements and notifies users when a counterparty does not meet them.
  • Documentation

    • Help text and translations updated to include the new /requirements command and related guidance.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 2, 2026

Walkthrough

Adds a configurable "counterparty requirements" feature: user model fields, a wizard for configuring minimum account age and completed orders, order-time validation to reject non‑compliant takers, new i18n strings across languages, and env limits in .env-sample.

Changes

Counterparty Requirements Feature

Layer / File(s) Summary
Data Shape
models/user.ts
Adds counterparty_requirements subdocument with min_days_using_bot and min_completed_orders (numbers ≥0, default 0) to UserDocument and schema.
Environment Limits
.env-sample
Introduces MAX_COUNTERPARTY_AGE_REQUIREMENT=30 and MAX_COUNTERPARTY_ORDERS_REQUIREMENT=10 for upper bounds on user-set thresholds.
Message Helper
bot/messages.ts
Exports notMeetingRequirementsMessage(ctx, user) which sends the localized not_meeting_requirements text to the user and logs send errors.
Requirements Wizard Scene (core)
bot/modules/user/scenes/requirements.ts
New Scenes.WizardScene allowing /counterpartyage <days>, /counterpartyorders <orders>, and /reset; parses/validates input (including env upper bounds), persists user.counterparty_requirements, sets localized feedback/errors, and edits the bot message only when content changes.
Scene Wiring
bot/modules/user/scenes/index.ts, bot/modules/user/index.ts, bot/middleware/stage.ts
Exports Requirements scene, registers /requirements command handler (enters Scenes.Requirements), and adds UserModule.Scenes.Requirements into stageMiddleware scenes list.
Order-time Validation
bot/modules/orders/takeOrder.ts
Adds meetsCounterpartyRequirements(ctx, user, orderCreator) check in takebuy and takesell after community-ban check; uses getUserAge and user.trades_completed, calls messages.notMeetingRequirementsMessage and aborts when taker doesn't meet creator's requirements.
Localization
locales/{en,de,es,fa,fr,it,ko,pt,ru,uk}.yaml
Adds user_requirements help block and keys: counterpartyage_updated, counterpartyorders_updated, requirements_reset, not_meeting_requirements, invalid_number, invalid_range; also adds /requirements to existing help text in multiple locales.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • mostronatorcoder

Poem

A rabbit checks each rule with care,
"Age and trades? Please do declare."
I hop, I write, I send the ping,
So only fitting partners ring. 🐰

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements counterparty requirements filtering but does not implement the specific /reject action requested in #648, which requires expiring invoices and re-posting orders immediately. Implement the /reject command as specified in #648 to expire invoices and re-post orders, or clarify if counterparty requirements serve as an alternative solution to the rejection scenario.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add counterparty requirements customization' accurately describes the main change: introducing a /requirements command for users to configure counterparty eligibility criteria for their orders.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing counterparty requirements customization: environment configuration, new wizard scene, locale strings, model updates, and gating order acceptance based on requirements—directly supporting the feature objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-counterparty-requirements-customization

Tip

💬 Introducing Slack Agent: Turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get your free trial and get 200 agent minutes per Slack user (a $50 value).


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bot/modules/user/scenes/requirements.ts`:
- Around line 33-35: The error heading is hardcoded; move it into i18n by adding
a locale key (e.g. "error.heading" or include the heading in each error key) and
change the errorText generator to use ctx.i18n.t to fetch that heading instead
of the literal '<strong>⚠️ ERROR</strong>' — modify the anonymous function
assigned to errorText (error => { ... }) to return ctx.i18n.t('error.heading') +
'\n' + ctx.i18n.t(error.i18n, error) or update error.i18n to a combined key and
call ctx.i18n.t(error.i18n, error), leaving ctx.i18n.t usage and error.i18n
intact.
- Around line 62-73: Both empty catch blocks (including the one in initHandler)
currently swallow Telegram/API failures; replace them with error handling that
logs the error and gives the user a recovery/fallback. Specifically, in
initHandler and the other try/catch: catch the thrown error, call your logger
(or console.error) with the error and context, notify the user with a short
fallback message via ctx.reply or ctx.answerCallbackQuery, and if the failure
was editing or sending the tracked message, attempt a safe fallback by sending a
new message (ctx.reply) and update state.message and state.message.text
accordingly so the wizard can continue; alternatively rethrow after logging if
you want global middleware to handle retries. Ensure you reference initHandler
and the state.message mutations when making the changes.
- Around line 89-91: The scene.command declarations are using leading slashes
which prevents Telegraf from matching them; update the scene.command calls for
the commands currently written as '/counterpartyage', '/counterpartyorders', and
'/reset' to use the plain command names without the slash (e.g.,
'counterpartyage', 'counterpartyorders', 'reset') where they are registered (the
scene.command(...) calls around the handlers that reference resetMessage and the
corresponding handler functions), leaving the rest of the handler logic
unchanged.

In `@locales/pt.yaml`:
- Around line 715-716: Update the Portuguese help strings for the keys that
start with "/counterpartyage" and "/counterpartyorders" to replace the Spanish
phrase "la contraparte" with the correct Portuguese "a contraparte" so the copy
is fully Portuguese (i.e., change "la contraparte" → "a contraparte" in both
lines).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8773ab1c-b912-4c1a-85d2-a9c2e8f7ef0d

📥 Commits

Reviewing files that changed from the base of the PR and between 41751eb and ff4a54a.

📒 Files selected for processing (18)
  • .env-sample
  • bot/messages.ts
  • bot/middleware/stage.ts
  • bot/modules/orders/takeOrder.ts
  • bot/modules/user/index.ts
  • bot/modules/user/scenes/index.ts
  • bot/modules/user/scenes/requirements.ts
  • locales/de.yaml
  • locales/en.yaml
  • locales/es.yaml
  • locales/fa.yaml
  • locales/fr.yaml
  • locales/it.yaml
  • locales/ko.yaml
  • locales/pt.yaml
  • locales/ru.yaml
  • locales/uk.yaml
  • models/user.ts

Comment thread bot/modules/user/scenes/requirements.ts
Comment thread bot/modules/user/scenes/requirements.ts Outdated
Comment thread bot/modules/user/scenes/requirements.ts
Comment thread locales/pt.yaml Outdated
Copy link
Copy Markdown
Contributor

@mostronatorcoder mostronatorcoder Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a strict pass on the full PR and I can't approve it in the current state.

  1. This PR is not scoped to issue #648 or even to the feature described in the title/body.

The advertised change is counterparty requirements, but this branch also includes unrelated Golden Honey Badger changes and pending payments messaging changes:

  • bot/commands.ts
  • bot/messages.ts
  • bot/ordersActions.ts
  • util/imageCache.ts
  • util/index.ts
  • models/order.ts
  • images/Honeybadger.png
  • jobs/pending_payments.ts
  • .env-sample (GOLDEN_HONEY_BADGER_PROBABILITY)
  • locale additions/removals for golden_honey_badger and pending_payment_failed_earnings

Those changes are behaviorally unrelated to counterparty requirements and make the review/risk surface much larger than necessary. Please split them into a separate PR.

  1. jobs/pending_payments.ts regresses withdrawal UX.

This PR removes the withdraw_earnings inline button from both the expired-invoice path and the failed-payment path, and also swaps pending_payment_failed_earnings for the generic pending_payment_failed message. That is not a neutral refactor. It changes the recovery path for community earnings withdrawals and should not ride along inside this feature PR.

  1. The linked issue is still not implemented.

The PR says Fixes #648, but issue #648 asks for a reject flow to immediately expire invoices and repost the order. This branch adds requirement-based filtering instead. Even if the filtering is useful, it does not satisfy the issue being auto-closed by this PR.

CI is green and the command-registration fixes from the review thread are in place, but the scope problem is enough for me to block this.

Please cut this down to the counterparty requirements feature only, or open separate PRs for the Honey Badger / pending-payments work.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
bot/modules/user/scenes/requirements.ts (1)

104-105: ⚡ Quick win

Use camelCase for local variables in this TypeScript scene.

min_days and min_orders should be renamed to camelCase for consistency with repository rules.

Proposed fix
-        const min_days = parseInt(days);
-        if (isNaN(min_days) || min_days < 0) throw new Error('NotValidNumber');
+        const minDays = parseInt(days);
+        if (isNaN(minDays) || minDays < 0) throw new Error('NotValidNumber');
@@
-        if (min_days > maxAge) {
+        if (minDays > maxAge) {
@@
-        user.counterparty_requirements.min_days_using_bot = min_days;
+        user.counterparty_requirements.min_days_using_bot = minDays;
@@
-          days: min_days,
+          days: minDays,
@@
-        const min_orders = parseInt(orders);
-        if (isNaN(min_orders) || min_orders < 0)
+        const minOrders = parseInt(orders);
+        if (isNaN(minOrders) || minOrders < 0)
           throw new Error('NotValidNumber');
@@
-        if (min_orders > maxOrders) {
+        if (minOrders > maxOrders) {
@@
-        user.counterparty_requirements.min_completed_orders = min_orders;
+        user.counterparty_requirements.min_completed_orders = minOrders;
@@
-          orders: min_orders,
+          orders: minOrders,
As per coding guidelines, `**/*.{ts,tsx}`: Use camelCase for functions and variables.

Also applies to: 151-153

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bot/modules/user/scenes/requirements.ts` around lines 104 - 105, Rename the
snake_case local variables min_days and min_orders to camelCase (minDays and
minOrders) throughout the requirements scene so they follow project naming
rules; update their declarations (e.g., the parseInt assignment) and every usage
(validation checks like isNaN/min < 0, error throws, and any later references
around the other mentioned block at lines ~151-153) to use minDays/minOrders to
avoid compile errors and keep naming consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bot/modules/user/scenes/requirements.ts`:
- Around line 131-137: The catch block that sets state.error = { i18n:
'invalid_number' } in the handler using ctx.scene.state (CommunityWizardState)
should only mark validation/parsing errors as 'invalid_number'; change the catch
to inspect the caught err (e.g., instanceof ValidationError, isAxiosError,
err.name/message or a custom validation check) and: for validation failures set
state.error.i18n = 'invalid_number' and call updateMessage(ctx); for all other
errors log the full error (using your logger) and set a different state.error
(e.g., i18n: 'internal_error' or a generic error key) or rethrow so
DB/Telegram/API failures aren’t presented as user input errors; apply the same
fix to the other catch block referenced around the second occurrence (the block
at lines 179-185) and ensure updateMessage(ctx) is called with the appropriate
state in each branch.

---

Nitpick comments:
In `@bot/modules/user/scenes/requirements.ts`:
- Around line 104-105: Rename the snake_case local variables min_days and
min_orders to camelCase (minDays and minOrders) throughout the requirements
scene so they follow project naming rules; update their declarations (e.g., the
parseInt assignment) and every usage (validation checks like isNaN/min < 0,
error throws, and any later references around the other mentioned block at lines
~151-153) to use minDays/minOrders to avoid compile errors and keep naming
consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 91a6125f-89c7-4b79-8e0c-a939fb19f297

📥 Commits

Reviewing files that changed from the base of the PR and between ff4a54a and 335e486.

📒 Files selected for processing (14)
  • .env-sample
  • bot/messages.ts
  • bot/modules/orders/takeOrder.ts
  • bot/modules/user/scenes/requirements.ts
  • locales/de.yaml
  • locales/en.yaml
  • locales/es.yaml
  • locales/fa.yaml
  • locales/fr.yaml
  • locales/it.yaml
  • locales/ko.yaml
  • locales/pt.yaml
  • locales/ru.yaml
  • locales/uk.yaml
✅ Files skipped from review due to trivial changes (8)
  • .env-sample
  • locales/pt.yaml
  • locales/ru.yaml
  • locales/fa.yaml
  • locales/ko.yaml
  • locales/en.yaml
  • locales/uk.yaml
  • locales/de.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
  • locales/fr.yaml
  • locales/it.yaml
  • bot/modules/orders/takeOrder.ts

Comment on lines +131 to +137
} catch (err) {
const state = ctx.scene.state as CommunityWizardState;
state.error = {
i18n: 'invalid_number',
};
await updateMessage(ctx);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid classifying all exceptions as invalid_number.

Right now, non-validation failures (e.g., DB save or Telegram API issues) are surfaced to users as input errors, which is misleading and makes incidents harder to diagnose.

Proposed fix
       } catch (err) {
         const state = ctx.scene.state as CommunityWizardState;
-        state.error = {
-          i18n: 'invalid_number',
-        };
+        if (err instanceof Error && err.message === 'NotValidNumber') {
+          state.error = { i18n: 'invalid_number' };
+        } else {
+          logger.error(err);
+          state.error = { i18n: 'generic_error' };
+        }
         await updateMessage(ctx);
       }
@@
       } catch (err) {
         const state = ctx.scene.state as CommunityWizardState;
-        state.error = {
-          i18n: 'invalid_number',
-        };
+        if (err instanceof Error && err.message === 'NotValidNumber') {
+          state.error = { i18n: 'invalid_number' };
+        } else {
+          logger.error(err);
+          state.error = { i18n: 'generic_error' };
+        }
         await updateMessage(ctx);
       }

Also applies to: 179-185

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bot/modules/user/scenes/requirements.ts` around lines 131 - 137, The catch
block that sets state.error = { i18n: 'invalid_number' } in the handler using
ctx.scene.state (CommunityWizardState) should only mark validation/parsing
errors as 'invalid_number'; change the catch to inspect the caught err (e.g.,
instanceof ValidationError, isAxiosError, err.name/message or a custom
validation check) and: for validation failures set state.error.i18n =
'invalid_number' and call updateMessage(ctx); for all other errors log the full
error (using your logger) and set a different state.error (e.g., i18n:
'internal_error' or a generic error key) or rethrow so DB/Telegram/API failures
aren’t presented as user input errors; apply the same fix to the other catch
block referenced around the second occurrence (the block at lines 179-185) and
ensure updateMessage(ctx) is called with the appropriate state in each branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add /reject order

1 participant