Skip to main content

Overview

Your Opinix wallet is your trading hub. It holds your funds and tracks all transactions, from deposits to trade settlements. Understanding your wallet is essential for successful trading.
Your wallet balance is stored securely in the database and updated in real-time as you trade.

Wallet structure

Your wallet consists of three key components:

Available balance

Funds ready to use for placing new orders

Locked balance

Funds currently in active orders

Total balance

Sum of available and locked balances

Balance flow

Here’s how your balance changes during trading:
1

Initial state

New accounts start with ₹0 available balance.
2

After deposit

Deposited funds go directly to available balance.
3

Order placed

Order cost moves from available to locked balance.
4

Order matched

Locked funds convert to trade position. Counter-party’s funds transfer to you.
5

Event settlement

Winning positions pay out to available balance.

Adding funds

Opinix uses Cashfree Payment Gateway for secure deposits supporting multiple payment methods.

Supported payment methods

Instant deposits via UPISupported apps:
  • Google Pay
  • PhonePe
  • Paytm
  • BHIM
  • Bank UPI apps
Features:
  • Instant credit
  • No processing fees (GST only)
  • ₹100 minimum
  • ₹1,00,000 maximum per transaction

Deposit process

Here’s how deposits work technically:
1

Navigate to deposit page

Go to /wallet/deposit or click “Wallet” → “Deposit” in navigation.
2

Enter amount

Choose your deposit amount:
  • Minimum: ₹100
  • Use quick-add buttons: +250, +500, +1000
  • Or enter custom amount
The deposit form component:
const [depositAmount, setDepositAmount] = useState(0);

const handleQuickAdd = (amount: number) => {
  setDepositAmount(prev => prev + amount);
};
3

Review summary

The summary panel calculates:
const rechargeAmount = depositAmount;
const gst = -(depositAmount * 0.18).toFixed(2);
const depositBalCredit = Number((depositAmount - Math.abs(gst)).toFixed(2));
const promotionalBalCredit = Math.abs(gst);
const netBalance = depositAmount;
Example for ₹500 deposit:
Recharge amount:        ₹500.00
GST applicable:        -₹90.00
Deposit bal. credit:    ₹410.00
Promotional bal. credit: +₹90.00
Net Balance:            ₹500.00
4

Initiate payment

Click “Recharge” to call the payment API:
const response = await fetch('/api/payment/initiate', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    customer_id: userId,
    customer_phone: phoneNumber,
    order_id: generatedOrderId,
    order_amount: depositAmount,
    order_currency: "INR"
  })
});
5

Cashfree integration

The backend forwards your request to Cashfree:
const response = await fetch(process.env.CASHFREE_URL!, {
  method: "POST",
  headers: {
    "accept": "application/json",
    "content-type": "application/json",
    "x-api-version": "2023-08-01",
    "x-client-id": process.env.CASHFREE_CLIENT_ID,
    "x-client-secret": process.env.CASHFREE_CLIENT_SECRET
  },
  body: JSON.stringify({
    customer_details: {
      customer_id: body.customer_id,
      customer_phone: body.customer_phone
    },
    order_id: body.order_id,
    order_amount: body.order_amount,
    order_currency: "INR",
    order_meta: {
      notify_url: process.env.CASHFREE_WEBHOOK_URL,
      payment_methods: "cc,dc,upi"
    }
  })
});
6

Complete payment

You’re redirected to Cashfree’s secure payment page:
  • Choose your payment method
  • Enter payment details
  • Complete authentication (OTP/PIN)
  • Cashfree processes the transaction
7

Payment verification

After payment, Cashfree redirects to:
/api/payment/status/[order_id]
The status endpoint verifies:
const response = await fetch(
  process.env.CASHFREE_URL + order_id,
  {
    method: "GET",
    headers: {
      "x-client-id": process.env.CASHFREE_CLIENT_ID,
      "x-client-secret": process.env.CASHFREE_CLIENT_SECRET
    }
  }
);

const data = await response.json();

if (data.order_status === "PAID") {
  // Success: redirect to home
  return NextResponse.redirect(new URL("/", req.url));
} else {
  // Failed: redirect to error page
  return NextResponse.redirect(new URL("/404", req.url));
}
8

Balance update

On successful payment, your wallet is credited:
export const DepositeMoneyInWallet = async (
  userId: string,
  amount: number
) => {
  const user = await prisma.user.findUnique({
    where: { id: userId }
  });
  
  if (!user) {
    return { success: false, message: "User not found" };
  }
  
  const newBalance = Math.max(0, user.balance + amount);
  
  await prisma.user.update({
    where: { id: userId },
    data: { balance: newBalance }
  });
  
  return { success: true, message: "Deposit successful" };
};
Never share payment OTPs or card CVVs with anyone. Opinix staff will never ask for this information.

Checking balance

You can view your balance in multiple places:

Header balance

Your current balance displays in the navigation header, updating in real-time as you trade.

Wallet page

The main wallet page (/wallet) shows:
  • Available balance
  • Locked balance (funds in active orders)
  • Total balance
  • Recent transactions
  • Deposit and withdraw buttons

Portfolio page

Your portfolio shows current returns, which represent unrealized profit/loss across all active positions.

Programmatic access

Get balance in server actions:
export async function getBalance(userId: string) {
  try {
    const user = await prisma.user.findUnique({
      where: { id: userId }
    });
    
    if (!user) {
      throw new Error("User not found");
    }
    
    return user.balance;
  } catch (error) {
    console.error("Error fetching balance:", error);
    throw error;
  }
}

Balance locking mechanism

When you place an order, the engine locks your funds to prevent double-spending.

For YES orders

if (side === "yes") {
  // Check sufficient balance
  if ((balances.get(userId)?.available || 0) < quantity * price) {
    throw new Error("Insufficient balance");
  }
  
  // Lock funds
  balances.get(userId).available -= quantity * price;
  balances.get(userId).locked += quantity * price;
}
Example:
  • You have ₹1000 available
  • Place YES order: 10 units at ₹50/unit = ₹500 total
  • After order:
    • Available: ₹500
    • Locked: ₹500

For NO orders

if (side === "no") {
  // Check sufficient balance
  if ((balances.get(userId)?.available || 0) < Number(quantity)) {
    throw new Error("Insufficient funds");
  }
  
  // Lock funds
  balances.get(userId).available -= Number(quantity);
  balances.get(userId).locked += Number(quantity);
}

Balance unlocking

Funds unlock when:
  1. Order is matched: Locked funds transfer to position
  2. Order is canceled: Funds return to available
  3. Event settles: Position converts to payout (winners) or expires (losers)
// On order cancellation
const leftQuantity = (order.quantity - order.filled) * order.price;
balances.get(order.userId).available += leftQuantity;
balances.get(order.userId).locked -= leftQuantity;

Transaction tracking

All wallet transactions are logged in the database for transparency and auditing.

Transaction types

  • DEPOSIT: Funds added via payment gateway
  • WITHDRAWAL: Funds transferred to bank account
  • ORDER_PLACED: Funds locked for order
  • ORDER_MATCHED: Trade executed
  • ORDER_CANCELED: Order canceled, funds unlocked
  • SETTLEMENT: Event outcome payout

Viewing transaction history

While not shown in the current UI, transactions are stored and can be queried:
const transactions = await prisma.transaction.findMany({
  where: { userId },
  orderBy: { createdAt: 'desc' },
  take: 50
});

GST and fees

Opinix applies 18% GST on all deposits as per Indian tax regulations.

How GST works

1

GST calculation

18% of deposit amount is calculated as GST:
const gst = depositAmount * 0.18;
2

Deposit credit

Your deposit balance receives the amount minus GST:
const depositBalCredit = depositAmount - gst;
3

Promotional credit

The GST amount is credited as promotional balance:
const promotionalBalCredit = gst;
4

Net result

You receive the full deposited amount:
const netBalance = depositBalCredit + promotionalBalCredit;
// netBalance === depositAmount
While GST is deducted, you receive an equivalent promotional credit, so your net balance equals your deposit amount.

Fee structure

  • Deposits: No fees (GST returned as promotional credit)
  • Trading: No commission on trades
  • Withdrawals: May incur payment gateway fees (check current rates)
  • Settlement: No fees on winnings payout

Withdrawals

Withdrawal functionality is under development. Currently, you can contact support for manual withdrawal requests.
When implemented, withdrawals will:
  1. Verify sufficient available balance
  2. Validate bank account details
  3. Process via Cashfree payout API
  4. Credit your bank account in 1-3 business days
  5. Deduct any applicable fees

Balance reconciliation

The engine ensures balance consistency:

Atomic updates

All balance changes happen in atomic database transactions to prevent race conditions.

Balance validation

Before every order:
if ((this.balances.get(userId)?.available || 0) < requiredAmount) {
  throw new Error("Insufficient balance");
}

Snapshot system

The engine saves balance snapshots every 3 seconds:
setInterval(() => {
  this.saveSnapshot();
}, 1000 * 3);
This allows recovery in case of crashes.

Troubleshooting

Possible causes:
  • Payment gateway webhook delay (wait 5-10 minutes)
  • Database sync issue
  • Browser cache (hard refresh the page)
If balance doesn’t update after 15 minutes, contact support with your order ID.
Check:
  • Your available balance (not total balance)
  • Existing locked funds in pending orders
  • Order cost = quantity × price
Cancel pending orders to free up locked funds.
Locked funds release when:
  • Order is matched (becomes position)
  • Order is canceled (returns to available)
  • Event closes (unmatched orders auto-cancel)
Check your portfolio for pending orders and cancel if needed.
If amount was deducted from your bank but Opinix shows failed:
  • Bank holds amount as pending
  • Reversal happens automatically in 5-7 business days
  • Contact your bank for faster reversal
Do not retry payment until reversal completes.

Best practices

Start small

Deposit a small amount initially to familiarize yourself with the platform before committing larger funds.

Track transactions

Keep records of your deposit order IDs for easy reconciliation if issues arise.

Manage locked funds

Regularly review and cancel unused orders to free up locked balance for new trades.

Monitor GST credits

Verify that promotional credits match GST deductions on each deposit.

Next steps