error('Please login'); $line = CreditLine::where('user_id', $user->id)->first(); if (!$line) { return $this->success([ 'has_credit' => 0, 'total_amount' => '0.00', 'used_amount' => '0.00', 'available_amount' => '0.00', 'daily_rate' => '0.0000', 'cycle_days' => 0, 'credit_score' => 0, 'status' => 0, ]); } $line->has_credit = 1; return $this->success($line); } public function creditSubscribe(Request $request) { $user_id = Token::getUserIdByToken(Token::getToken()); $user = \App\Users::find($user_id); if (!$user) return $this->error('Please login'); $project_id = intval($request->input('project_id')); $amount = floatval($request->input('amount')); if (!$project_id || $amount <= 0) return $this->error('Invalid params'); $project = IeoProject::find($project_id); if (!$project || $project->status != 1) return $this->error('IEO not active'); if ($amount < $project->min_buy) return $this->error('Min: ' . $project->min_buy . ' USDC'); if ($project->max_buy > 0 && $amount > $project->max_buy) return $this->error('Max: ' . $project->max_buy . ' USDC'); $existingNormal = DB::table('ieo_order')->where('user_id', $user->id)->where('project_id', $project_id)->where('status', '!=', 2)->exists(); if ($existingNormal) return $this->error('Already subscribed via normal IEO'); DB::beginTransaction(); try { $line = CreditLine::where('user_id', $user->id)->lockForUpdate()->first(); if (!$line || $line->status != 1) { DB::rollBack(); return $this->error('No active credit line'); } if ($line->available_amount < $amount) { DB::rollBack(); return $this->error('Insufficient credit'); } $existingCredit = CreditIeoOrder::where('user_id', $user->id)->where('project_id', $project_id)->whereIn('status', [0, 1])->exists(); if ($existingCredit) { DB::rollBack(); return $this->error('Already subscribed via credit'); } $line->available_amount = bc_sub($line->available_amount, $amount, 6); $line->used_amount = bc_add($line->used_amount, $amount, 6); $line->save(); $token_amount = $project->token_price > 0 ? sprintf("%.6f", $amount / $project->token_price) : 0; $order = CreditIeoOrder::create([ 'user_id' => $user->id, 'credit_line_id' => $line->id, 'project_id' => $project_id, 'amount' => $amount, 'token_amount' => $token_amount, 'status' => 0, 'repaid_amount' => 0, 'interest' => 0, ]); AccountLog::insertLog( ['user_id' => $user->id, 'value' => -$amount, 'info' => 'Credit IEO subscribe #' . $project->name, 'type' => AccountLog::MICRO_TRADE_SUBMIT, 'currency' => 3], ['balance_type' => 1, 'wallet_id' => 0, 'lock_type' => 0, 'before' => bc_add($line->available_amount, $amount, 6), 'change' => -$amount, 'after' => $line->available_amount] ); DB::commit(); return $this->success(['order_id' => $order->id, 'msg' => 'Credit subscription successful']); } catch (\Exception $e) { DB::rollBack(); return $this->error($e->getMessage()); } } public function myCreditOrders(Request $request) { $user_id = Token::getUserIdByToken(Token::getToken()); $user = \App\Users::find($user_id); if (!$user) return $this->error('Please login'); $list = CreditIeoOrder::where('user_id', $user->id) ->with('project:id,name,symbol,token_price,listing_time,unlock_time') ->orderBy('id', 'desc') ->get(); $statusMap = ['0' => 'Pending Repayment', '1' => 'Repaid', '3' => 'Overdue']; foreach ($list as $item) { $item->status_text = $statusMap[$item->status] ?? ''; $line = $item->creditLine ?? CreditLine::find($item->credit_line_id); $dailyRate = $line ? floatval($line->daily_rate) : 0; $createdTs = strtotime((string)$item->created_at); if (!$createdTs) $createdTs = time(); $days = max(1, (int)ceil((time() - $createdTs) / 86400)); $item->accrued_interest = sprintf('%.6f', $item->amount * $dailyRate * $days); $item->repay_total = sprintf('%.6f', $item->amount + ($item->amount * $dailyRate * $days)); $item->days_elapsed = $days; } return $this->success($list); } public function repay(Request $request) { $user_id = Token::getUserIdByToken(Token::getToken()); $user = \App\Users::find($user_id); if (!$user) return $this->error('Please login'); $order_id = intval($request->input('order_id')); if (!$order_id) return $this->error('Invalid order'); DB::beginTransaction(); try { $order = CreditIeoOrder::where('id', $order_id)->where('user_id', $user->id)->lockForUpdate()->first(); if (!$order) { DB::rollBack(); return $this->error('Order not found'); } if ($order->status == 1) { DB::rollBack(); return $this->error('Already repaid'); } $line = CreditLine::where('id', $order->credit_line_id)->lockForUpdate()->first(); if (!$line) { DB::rollBack(); return $this->error('Credit line missing'); } $dailyRate = floatval($line->daily_rate); $createdTs = strtotime((string)$order->created_at); if (!$createdTs) $createdTs = time(); $days = max(1, (int)ceil((time() - $createdTs) / 86400)); $interest = sprintf('%.6f', $order->amount * $dailyRate * $days); $total = bc_add($order->amount, $interest, 6); $wallet = UsersWallet::where('user_id', $user->id)->where('currency', 3)->lockForUpdate()->first(); if (!$wallet || $wallet->legal_balance < $total) { DB::rollBack(); return $this->error('Insufficient balance to repay'); } $before = $wallet->legal_balance; $wallet->legal_balance = bc_sub($wallet->legal_balance, $total, 6); $wallet->save(); AccountLog::insertLog( ['user_id' => $user->id, 'value' => -$total, 'info' => 'Credit IEO Repay #' . $order->id, 'type' => AccountLog::IEO_OPERATION, 'currency' => 3], ['balance_type' => 1, 'wallet_id' => $wallet->id, 'lock_type' => 0, 'before' => $before, 'change' => -$total, 'after' => $wallet->legal_balance] ); $line->used_amount = max(0, bc_sub($line->used_amount, $order->amount, 6)); $line->available_amount = bc_add($line->available_amount, $order->amount, 6); if ($line->available_amount > $line->total_amount) { $line->available_amount = $line->total_amount; } $line->save(); $order->interest = $interest; $order->repaid_amount = $total; $order->status = 1; $order->save(); if ($order->token_amount > 0) { $project = \App\IeoProject::find($order->project_id); if ($project) { $tokenCurrency = \App\Currency::where('name', $project->symbol)->first(); if ($tokenCurrency) { $tokenWallet = UsersWallet::where('user_id', $user->id) ->where('currency', $tokenCurrency->id)->lockForUpdate()->first(); if ($tokenWallet) { $beforeToken = $tokenWallet->change_balance; $tokenWallet->change_balance = bc_add($tokenWallet->change_balance, $order->token_amount, 6); $tokenWallet->save(); AccountLog::insertLog( ['user_id' => $user->id, 'value' => $order->token_amount, 'info' => 'Credit IEO Token Unlock - ' . $project->name, 'type' => AccountLog::IEO_OPERATION, 'currency' => $tokenCurrency->id], ['balance_type' => 2, 'wallet_id' => $tokenWallet->id, 'lock_type' => 0, 'before' => $beforeToken, 'change' => $order->token_amount, 'after' => $tokenWallet->change_balance] ); } } } } DB::commit(); return $this->success(['msg' => 'Repaid', 'total' => $total, 'interest' => $interest]); } catch (\Exception $e) { DB::rollBack(); return $this->error($e->getMessage()); } } public function repayAll(Request $request) { $user_id = Token::getUserIdByToken(Token::getToken()); $user = \App\Users::find($user_id); if (!$user) return $this->error('Please login'); $credit = CreditLine::where('user_id', $user->id)->lockForUpdate()->first(); if (!$credit) return $this->error('No credit line'); $orders = CreditIeoOrder::where('user_id', $user->id) ->whereIn('status', [0, 3]) ->get(); if ($orders->isEmpty()) return $this->error('No pending orders'); $totalRepay = 0; foreach ($orders as $order) { $days = max(1, ceil((time() - strtotime($order->created_at)) / 86400)); $interest = sprintf('%.6f', $order->amount * floatval($credit->daily_rate) * $days); $totalRepay = bc_add($totalRepay, bc_add($order->amount, $interest, 6), 6); } $wallet = UsersWallet::where('user_id', $user->id)->where('currency', 3)->lockForUpdate()->first(); if (!$wallet || bc_comp($wallet->legal_balance, $totalRepay) < 0) { return $this->error('Insufficient balance, need ' . $totalRepay . ' USDC'); } DB::beginTransaction(); try { $before = $wallet->legal_balance; foreach ($orders as $order) { $days = max(1, ceil((time() - strtotime($order->created_at)) / 86400)); $interest = sprintf('%.6f', $order->amount * floatval($credit->daily_rate) * $days); $repayAmount = bc_add($order->amount, $interest, 6); $wallet->legal_balance = bc_sub($wallet->legal_balance, $repayAmount, 6); $credit->used_amount = bc_sub($credit->used_amount, $order->amount, 6); $credit->available_amount = bc_add($credit->available_amount, $order->amount, 6); $order->update(['status' => 1, 'repaid_amount' => $repayAmount, 'interest' => $interest]); } $wallet->save(); AccountLog::insertLog( ['user_id' => $user->id, 'value' => -$totalRepay, 'info' => 'Credit IEO Repay All', 'type' => AccountLog::IEO_OPERATION, 'currency' => 3], ['balance_type' => 1, 'wallet_id' => $wallet->id, 'lock_type' => 0, 'before' => $before, 'change' => -$totalRepay, 'after' => $wallet->legal_balance] ); if (bc_comp($credit->available_amount, $credit->total_amount) > 0) { $credit->available_amount = $credit->total_amount; } $credit->save(); DB::commit(); return $this->success('All orders repaid'); } catch (\Throwable $e) { DB::rollBack(); return $this->error($e->getMessage()); } } }