Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ which now builds a `Jan3AccountsManager`) and delegates provisioning to it.
## WapuPay (Argentine direct-fiat)

`wapupay.py` lets a user pay an Argentine bank account in **ARS**, funded with
**USDT on Liquid**. WapuPay's API is called **directly** (`https://be-prod.wapu.app`),
**USDT or L-BTC on Liquid**. WapuPay's API is called **directly** (`https://be-prod.wapu.app`),
not through Ankara. Each call carries WapuPay's own **`X-API-Key`**;
`wapupay_create_order` returns a Liquid USDT funding address; the user pays it
`wapupay_create_order` returns a Liquid funding address; the user pays it
with `lw_send_asset` (no auto-pay). `wapupay_exchange_rates` is **public** (no key).

WapuPay logic (orders, quotes, `X-API-Key` calls)
Expand Down Expand Up @@ -219,7 +219,10 @@ lives in `wapupay.py`.
- **Enabled by default.** All `jan3_*` / `wapupay_*` tools ship enabled (not in
`features._SHIPPED_DISABLED`). Business calls still need a key — env var or
provisioned via `wapupay_provision_account`.
- **Rail pinned** to Liquid USDT; WapuPay rejects any other funding rail (400).
- **Funding rail is selectable per order** — USDT (default) or L-BTC — both
settle from a Liquid address (`network=LIQUID`). The quote/preview endpoint
is USDT-only (LBTC returns a 500), so `wapupay_quote` and the create-order
confirmation preview never pass `funding_method`.
- JAN3 sessions persist per-email at `~/.aqua/jan3/{email}.json`; the
provisioned API key and order records persist under `~/.aqua/wapupay/` — all at
`0o600`. Bank PII + tokens + API key are never logged (see `ankara._redact` /
Expand Down
2 changes: 1 addition & 1 deletion scripts/prompts/prompt_test_wapupay.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ as the refund address. Show me the funding instructions but DO NOT pay yet.
- Invokes `wapupay_create_order(amount_ars="10000", alias="test.alias.mp", receiver_name="Test Receiver", refund_address="lq1qqw4...k6lng")`
- Returns `tentative_id`, `status` (`FUNDING_ISSUED`), `address_destination` (Liquid `lq1…/ex1…/VJL…`),
`asset_id` (USDT on Liquid), `funding_amount_usdt`, `total_amount_usdt`,
`total_funding_amount_base_units`, `funding_expires_at`, `pay_instructions`, `qr_code_path`
`total_funding_amount_base_units`, `expires_at`, `pay_instructions`, `qr_code_path`
- ⚠️ The agent shows the funding address/QR **but must NOT call `lw_send_asset`** — keep this dry

---
Expand Down
2 changes: 1 addition & 1 deletion src/aqua/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Agentic AQUA - Manage Liquid Network and Bitcoin wallets through AI assistants."""

__version__ = "0.5.1b1"
__version__ = "0.5.2"
28 changes: 18 additions & 10 deletions src/aqua/cli/wapupay.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""WapuPay CLI — Argentine direct-fiat payments funded with USDT on Liquid.
"""WapuPay CLI — Argentine direct-fiat payments funded with USDT or L-BTC on Liquid.

Pay an Argentine bank account (alias / CBU / CVU) in ARS via P2P swap, funded with USDT on
Liquid. These commands call WapuPay directly and require `WAPUPAY_API_KEY` set in
the environment. `create-order` returns a Liquid USDT address to fund; pay it with
Pay an Argentine bank account (alias / CBU / CVU) in ARS via P2P swap, funded with USDT or
L-BTC on Liquid. These commands call WapuPay directly and require `WAPUPAY_API_KEY` set in
the environment. `create-order` returns a Liquid funding address; pay it with
`aqua liquid send-asset` and WapuPay settles the ARS payout.
"""

Expand Down Expand Up @@ -30,10 +30,10 @@

@click.group()
def wapupay():
"""WapuPay — pay Argentine bank accounts in ARS, funded with USDT on Liquid.
"""WapuPay — pay Argentine bank accounts in ARS, funded with USDT or L-BTC on Liquid.

Calls WapuPay directly; set WAPUPAY_API_KEY in your environment first.
`create-order` returns a Liquid USDT address to fund — pay it with
`create-order` returns a Liquid address to fund — pay it with
`aqua liquid send-asset` and WapuPay settles the pesos.
"""

Expand Down Expand Up @@ -90,18 +90,25 @@ def quote(ctx, amount_ars, transfer_type, alias):
"--wallet-name", default="default", show_default=True,
help="Wallet you intend to fund from.",
)
@click.option(
"--funding-method", "funding_method",
type=click.Choice(["USDT", "LBTC"]), default="USDT", show_default=True,
help="Funding rail: USDT (default) or LBTC. Both settle on Liquid; LBTC "
"is paid as L-BTC sats, USDT as USDT base units.",
)
@click.option(
"--yes", "-y", "skip_confirm", is_flag=True, default=False,
help="Skip the interactive quote-confirmation prompt.",
)
@click.pass_obj
def create_order(ctx, amount_ars, alias, transfer_type, receiver_name, refund_address,
wallet_name, skip_confirm):
"""Create a direct-fiat order and get a Liquid USDT funding address.
wallet_name, funding_method, skip_confirm):
"""Create a direct-fiat order and get a Liquid funding address.

Fetches a quote for confirmation, then creates the order and issues funding
instructions. Fund the returned address with `aqua liquid send-asset`;
WapuPay then pays the pesos. This command never broadcasts a payment.
instructions (USDT by default, or L-BTC via --funding-method). Fund the
returned address with `aqua liquid send-asset`; WapuPay then pays the pesos.
This command never broadcasts a payment.
"""
if refund_address and refund_address.strip():
try:
Expand Down Expand Up @@ -137,6 +144,7 @@ def create_order(ctx, amount_ars, alias, transfer_type, receiver_name, refund_ad
receiver_name=receiver_name,
refund_address=refund_address,
wallet_name=wallet_name,
funding_method=funding_method,
),
)

Expand Down
24 changes: 19 additions & 5 deletions src/aqua/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1137,12 +1137,14 @@
},
"wapupay_create_order": {
"description": (
"Create a WapuPay order and get a Liquid USDT funding address. "
"Create a WapuPay order and get a Liquid funding address. Funds from "
"USDT (default) or L-BTC — both settle from a Liquid address. "
"Creates the tentative (freezing the quote) and issues "
"funding instructions. Returns address_destination (Liquid), asset_id "
"(USDT), funding_amount_usdt, total_amount_usdt, "
"total_funding_amount_base_units, funding_expires_at and a QR. Pay the "
"TOTAL with lw_send_asset (amount = total_funding_amount_base_units); "
"funding instructions. Returns address_destination (Liquid), asset_id, "
"funding_amount_usdt, total_amount_usdt, "
"total_funding_amount_base_units (for USDT), funding_amount_sat (for LBTC), "
"expires_at and a QR. Pay the TOTAL with lw_send_asset (amount "
"and unit depend on funding_method — follow pay_instructions); "
"WapuPay then makes a P2P payer settle ARS to the bank account. Does NOT broadcast the "
"payment itself — confirm the quote with the user first via wapupay_quote."
),
Expand All @@ -1167,6 +1169,18 @@
"receiver_name": {"type": "string", "description": "Recipient name (optional)"},
"refund_address": {"type": "string", "description": "Liquid mainnet refund address (lq1…/ex1…) if funding cannot execute (optional); validated before the order is created"},
"wallet_name": {"type": "string", "default": "default", "description": "Wallet you intend to fund from (recorded for tracking)"},
"funding_method": {
"type": "string",
"enum": ["USDT", "LBTC"],
"default": "USDT",
"description": (
"Funding rail for the payout — 'USDT' (default) or 'LBTC'. Both "
"settle from a Liquid address. For 'LBTC', WapuPay returns "
"funding_amount_sat (the exact sats of L-BTC to send); for 'USDT', "
"send total_funding_amount_base_units. Follow the returned "
"pay_instructions for the exact amount and unit."
),
},
},
"required": ["amount_ars", "alias"],
},
Expand Down
24 changes: 15 additions & 9 deletions src/aqua/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1223,21 +1223,24 @@ def wapupay_create_order(
receiver_name: str | None = None,
refund_address: str | None = None,
wallet_name: str = "default",
funding_method: str = "USDT",
) -> dict[str, Any]:
"""Create a WapuPay direct-fiat order and get a Liquid USDT funding address.
"""Create a WapuPay direct-fiat order and get a Liquid funding address.

Creates the payment tentative (freezing the quote) and immediately issues
funding instructions. The order is persisted before funding, so if funding
fails you get the order back with `funded=False` and can retry via
`wapupay_fund_order` — no silent failure.

The result includes `address_destination` (a Liquid address), `asset_id`
(USDT on Liquid), `funding_amount_usdt`, `total_amount_usdt`,
`total_funding_amount_base_units`, and `funding_expires_at`. Pay the TOTAL
with `lw_send_asset` (amount = `total_funding_amount_base_units`, the exact
total_amount_usdt in USDT base units; asset_id from the response); WapuPay
then settles `amount_ars` ARS to the bank account. This tool never
broadcasts a payment itself.
The result includes `address_destination` (a Liquid address),
`funding_amount_usdt`, `total_amount_usdt`, `expires_at`, and a
`pay_instructions` field that tells you the exact amount and unit to send —
follow it. For the default `USDT` rail, pay the TOTAL with `lw_send_asset`
(amount = `total_funding_amount_base_units`, the exact total_amount_usdt in
USDT base units; asset_id from the response). For the `LBTC` rail, WapuPay
returns `funding_amount_sat` instead, and you send that many sats of L-BTC
via `lw_send_asset`. WapuPay then settles `amount_ars` ARS to the bank
account. This tool never broadcasts a payment itself.

Args:
amount_ars: amount to pay in Argentine pesos (decimal string, e.g. "10000").
Expand All @@ -1254,11 +1257,13 @@ def wapupay_create_order(
refund_address: Liquid mainnet address (lq1…/ex1…/VJL…) for a refund if funding
cannot execute (optional); validated before the order is created.
wallet_name: wallet you intend to fund from (recorded for tracking).
funding_method: funding rail — "USDT" (default) or "LBTC"; both settle
from a Liquid address.

Returns:
The order record incl. tentative_id, status, address_destination,
asset_id, funding_amount_usdt, total_amount_usdt,
total_funding_amount_base_units, funding_expires_at, funded,
total_funding_amount_base_units, expires_at, funded,
pay_instructions, and qr_code_path (QR of the funding address).
"""
result = get_wapupay_manager().create_order(
Expand All @@ -1268,6 +1273,7 @@ def wapupay_create_order(
receiver_name=receiver_name,
refund_address=refund_address,
wallet_name=wallet_name,
funding_method=funding_method,
)
return _attach_deposit_qr(result, "address_destination")

Expand Down
Loading
Loading