# MAVRIC Pay — payment gateway for other platforms

Hand this folder to any vendor that wants to take **MAVRIC** as a payment token.

Shoppers invoice in **USDT**. The equal **MAVRIC** is debited from their wallet at the live price: **CEX ticker** if MAVRIC is listed and the tick is fresh, otherwise the **DEX AMM** spot. Merchant receives MAVRIC (net after the same 85 / 7.5 / 7.5 exit split as DEX). Your backend confirms **`usdtValue` matches the invoice**, then you fulfill. Treasury cannot be a payment destination. Admin enables Merchant Pay **anytime** with `setUtilityPaymentsEnabled` — no 5,000 treasury wait. On-chain `pay()` is disabled; checkout uses `payUsdtValue` only.

BSC TESTNET token + gateway are filled in `contracts/addresses.testnet.json` and the snippets below. Empty `gateway` still uses the simulator host (`pay/developers.html`) — that demo is **not** a chain payment. Mainnet MAVRIC addresses stay empty until a verified deploy.

## What you give a vendor developer

| File | Role |
| --- | --- |
| `mavric-pay.sdk.js` | Browser checkout + `verify` (no npm) |
| `verify.py` | Server-side `eth_call` confirm (Python stdlib) |
| `examples/checkout.html` | Copy-paste button |
| `developers.html` | Docs + sandbox widget |
| `../contracts/MavricPayGateway.sol` | On-chain gateway |
| `../contracts/abis/MavricPayGateway.json` | ABI |

## 1. Browser checkout (vendor site)

```html
<script>
  window.MAVRIC_PAY_CONFIG = {
    chainId: '0x61',          // BSC TESTNET. Mainnet is '0x38'
    token:   '0x4d3Ce8d57f73Caa7E3f1ABD1514e5BeDdf791cf4',
    gateway: '0xaFc995166E924090e27C338A0eC068627Dacf081',
    treasury: '0x52CAa950e3e3d4F1560f595fDFFaf2B05F72c1d1',
    rpcUrl:  'https://bsc-testnet-rpc.publicnode.com'
  };
</script>
<script src="https://YOUR_DOMAIN/pay/mavric-pay.sdk.js"></script>
<button id="pay-mavric" type="button">Pay with MAVRIC</button>
<script>
  document.getElementById('pay-mavric').onclick = function () {
    MavricPay.checkout({
      merchant: '0xYOUR_MERCHANT_WALLET',
      amount: '10',                 // invoice USDT; MAVRIC debit = USDT / live price
      orderId: 'INV-' + Date.now(), // unique per invoice; 1–64 chars
      onPaid: function (rec) {
        // UX only. Never fulfill from this browser callback.
      },
      onError: function (err) { alert(err.message); }
    });
  };
</script>
```

`orderId` is hashed with keccak-256 (UTF-8). The same merchant + orderId cannot be paid twice.

Optional: merchant self-registers on the gateway (`registerMerchant("Shop name")`) so MAVRIC admin can pause that wallet. Unregistered wallets can still receive payments.

## 2. Backend verify (required)

Never fulfill from `onPaid` alone. Confirm with `getPayment` **and** `getPaymentQuote` so `usdtValue` matches the invoice:

```bash
python pay/verify.py --merchant 0xMERCHANT --order INV-1001 --gateway 0xGATEWAY --rpc https://bsc-testnet-rpc.publicnode.com --expect-usdt 10
```

Exit `0` only if paid **and** `usdtValue` meets `--expect-usdt`. Exit `3` means paid but underpaid. `amount` is **net MAVRIC to the merchant**, not invoice USDT.

Or from Node / any stack: `eth_call` `getPaymentQuote(address,bytes32)` on the gateway. The SDK `MavricPay.verify` is a convenience read — still not a substitute for your server.

## 3. On-chain deploy (MAVRIC operator)

1. Deploy `MavricPayGateway(initialOwner, mavricToken)`.
2. Call `setProtocol(protocol)` once.
3. Owner calls `MavricProtocol.setUtilityPaymentsEnabled(true)` when a merchant is tied up. **No 5,000 treasury wait.** DEX buy / CEX listing still use that gate.
4. Put token + gateway + treasury addresses in `MAVRIC_PAY_CONFIG` and in `CONTRACTS.*.pay` / `.treasury`.

Shopper flow: `approve(gateway, maxMavric)` then `payUsdtValue(merchant, orderId, usdtAmount, maxMavric)`. The SDK waits for the mined receipt and re-reads `getPayment` before `onPaid`. Equal MAVRIC moves payer → merchant at `Protocol.paySpotPrice()` (CEX if listed and fresh, else DEX), then 85 / 7.5 / 7.5 exit split.

On-chain CEX price is **not** an HTTP fetch (Solidity cannot call Binance). After you list, a keeper must call `setCexSpotPrice`. If that tick is missing or older than 1 hour, Pay uses DEX AMM. The simulator fetches Binance/MEXC tickers in the browser when you set a symbol.

## Honest limits

- Empty `gateway` = simulator / demo only.
- This is not Stripe, not a card processor, and not a CEX listing API.
- Replay protection is per `(merchant, orderId)`, not per shopper.
- `utilityPaymentsEnabled` must be on or `payUsdtValue` reverts. That switch is admin-anytime; it does not wait on treasury 5,000 MAVRIC.
- Checking `isPaid` alone is not enough. Always compare `usdtValue` to the invoice.
- No app can block stolen keys, a compromised device, or every unknown attack.
