From f60e4ca3a56f2a250b336fcb1ba9b6446c94cc31 Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Thu, 28 Aug 2025 14:07:09 +0400 Subject: [PATCH] added rough mainnet implementation and added backup contact for email --- .dockerignore | 14 ++++++++++++++ Dockerfile | 41 +++++++++++++++++++++++++++++++++++++++++ app/dapp/page.tsx | 24 ++++++++++++++++++++---- config/web3.ts | 3 ++- docker-compose.yml | 20 +++++++------------- next.config.ts | 2 ++ 6 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b24c193 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +node_modules +.next +.git +.gitignore +Dockerfile* +README.md +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.env* +.dockerignore +**/*.local.* +**/*.test.* +**/__tests__/** diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..727d2d3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +# syntax=docker/dockerfile:1 + +# 1) Install dependencies +FROM --platform=linux/amd64 node:20-alpine AS deps +WORKDIR /app +ENV CI=true +# Install system deps commonly needed by Next.js +RUN apk add --no-cache libc6-compat +COPY package.json package-lock.json ./ +RUN npm ci --legacy-peer-deps --no-audit --no-fund + +# 2) Build the app +FROM --platform=linux/amd64 node:20-alpine AS builder +WORKDIR /app +ENV NEXT_TELEMETRY_DISABLED=1 +COPY --from=deps /app/node_modules ./node_modules +COPY . . +# Allow passing public env vars at build time +ARG NEXT_PUBLIC_NTFY_URL +ARG NEXT_PUBLIC_SCHEDY_URL +ENV NEXT_PUBLIC_NTFY_URL=${NEXT_PUBLIC_NTFY_URL:-/ntfy} +ENV NEXT_PUBLIC_SCHEDY_URL=${NEXT_PUBLIC_SCHEDY_URL:-/schedy} +RUN npm run build + +# 3) Run with standalone output +FROM --platform=linux/amd64 node:20-alpine AS runner +WORKDIR /app +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +# Create non-root user +RUN adduser -D nextjs +# Copy the minimal standalone output +COPY --from=builder /app/public ./public +COPY --from=builder /app/.next/standalone ./ +COPY --from=builder /app/.next/static ./.next/static +COPY --from=builder /app/.next/BUILD_ID ./.next/BUILD_ID +# Expose and run +EXPOSE 3000 +ENV PORT=3000 HOST=0.0.0.0 +USER nextjs +CMD ["node", "server.js"] diff --git a/app/dapp/page.tsx b/app/dapp/page.tsx index d88cae3..e9cebb8 100644 --- a/app/dapp/page.tsx +++ b/app/dapp/page.tsx @@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from 'react'; import { useAccount, useChainId, useReadContract, useReadContracts, useSwitchChain, usePublicClient, useWriteContract, useSendTransaction } from 'wagmi'; -import { base, arbitrum } from 'wagmi/chains'; +import { base, arbitrum, mainnet } from 'wagmi/chains'; import { Abi, parseUnits } from 'viem'; import debtAbi from '@/ABIs/mortgagefiusdccbbtcupgraded.json'; import Link from 'next/link'; @@ -21,6 +21,8 @@ const erc721Abi = [ { type: 'function', name: 'tokenOfOwnerByIndex', stateMutability: 'view', inputs: [{ name: 'owner', type: 'address' }, { name: 'index', type: 'uint256' }], outputs: [{ type: 'uint256' }] }, ] as const satisfies Abi; +const ENABLE_MAINNET = process.env.NEXT_PUBLIC_ENABLE_MAINNET === 'true'; + const DEFAULTS = { [base.id]: { nft: '0xcc9a350c5b1e1c9ecd23d376e6618cdfd6bbbdbe', @@ -30,10 +32,17 @@ const DEFAULTS = { nft: '0xedE6F5F8A9D6B90b1392Dcc9E7FD8A5B0192Bfe1', debt: '0x9Be2Cf73E62DD3b5dF4334D9A36888394822A33F', }, + ...(ENABLE_MAINNET ? { + [mainnet.id]: { + // Dummy placeholders for future USDC-WETH mainnet vault + nft: '0x0000000000000000000000000000000000000001', + debt: '0x0000000000000000000000000000000000000002', + }, + } : {}), } as const; // Presets per chain (selectable pairs) -const PRESETS: Record = { +const PRESETS: Partial> = { [base.id]: [ { key: 'cbBTC-USDC', label: 'cbBTC-USDC', nft: '0xcc9a350c5b1e1c9ecd23d376e6618cdfd6bbbdbe', debt: '0xe93131620945a1273b48f57f453983d270b62dc7' }, { key: 'WETH-USDC', label: 'WETH-USDC', nft: '0xab825f45e9e5d2459fb7a1527a8d0ca082c582f4', debt: '0x1be87d273d47c3832ab7853812e9a995a4de9eea' }, @@ -41,6 +50,11 @@ const PRESETS: Record 600) return; // ignore stale links >10min const net = String(parsed.network || '').toUpperCase(); const presetIdx = Math.max(1, Number(parsed.preset || 1)); - const nextChainId = net === 'BASE' ? base.id : ((net === 'ARBITRUM' || net === 'ARB') ? arbitrum.id : selectedChainId); + const nextChainId = net === 'BASE' ? base.id + : ((net === 'ARBITRUM' || net === 'ARB') ? arbitrum.id + : (ENABLE_MAINNET && net === 'MAINNET' ? mainnet.id : selectedChainId)); if (nextChainId !== selectedChainId) { setSelectedChainId(nextChainId); loadChainDefaults(nextChainId); @@ -720,7 +736,7 @@ export default function DappPage() { const debtRemaining = (row as any)?.debtAtThisSize as bigint | undefined; const origin = (typeof window !== 'undefined' && window.location?.origin) ? window.location.origin : 'https://markets.mortgagefi.app'; const dappUrl = `${origin}/dapp`; - const networkSlug = selectedChainId === base.id ? 'BASE' : (selectedChainId === arbitrum.id ? 'ARBITRUM' : 'UNKNOWN'); + const networkSlug = selectedChainId === base.id ? 'BASE' : (selectedChainId === arbitrum.id ? 'ARBITRUM' : (selectedChainId === mainnet.id ? 'MAINNET' : 'UNKNOWN')); const presetIdx = Math.max(0, (PRESETS[selectedChainId]?.findIndex(p => p.key === presetKey) ?? 0)) + 1; // 1-based const positionUrl = `${origin}/dapp/position/${networkSlug}/${presetIdx}/${row.tokenId.toString()}`; const humanLeft = human(offset); diff --git a/config/web3.ts b/config/web3.ts index fcf739e..e1a2d8b 100644 --- a/config/web3.ts +++ b/config/web3.ts @@ -12,9 +12,10 @@ const metadata = { // Prefer custom RPCs to avoid public-provider rate limits (429) const baseRpc = process.env.NEXT_PUBLIC_RPC_BASE; const arbitrumRpc = process.env.NEXT_PUBLIC_RPC_ARBITRUM; +const enableMainnet = process.env.NEXT_PUBLIC_ENABLE_MAINNET === 'true'; export const config = createConfig({ - chains: [base, arbitrum, mainnet, sepolia], + chains: [base, arbitrum, ...(enableMainnet ? [mainnet] : []), sepolia], transports: { [base.id]: baseRpc ? http(baseRpc, { batch: true, retryCount: 2, retryDelay: 250 }) : http(undefined, { batch: true, retryCount: 2, retryDelay: 250 }), [arbitrum.id]: arbitrumRpc ? http(arbitrumRpc, { batch: true, retryCount: 2, retryDelay: 250 }) : http(undefined, { batch: true, retryCount: 2, retryDelay: 250 }), diff --git a/docker-compose.yml b/docker-compose.yml index 1124b51..f009ac2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,29 +30,23 @@ services: - TZ=UTC ports: - "8080:8080" + volumes: + # Persist BadgerDB data so schedules survive restarts + - ../data/schedy:/data restart: unless-stopped frontend: - image: node:20-alpine + # image: node:20-alpine + image: git.manko.yoga/manawenuz/mortgagefi-frontend:alert platform: linux/amd64 - container_name: mortgagefi-frontend - working_dir: /app + # container_name: mortgagefi-frontend env_file: .env.local environment: - HOST=0.0.0.0 - PORT=3000 - NEXT_PUBLIC_NTFY_URL=${NEXT_PUBLIC_NTFY_URL:-/ntfy} - NEXT_PUBLIC_SCHEDY_URL=${NEXT_PUBLIC_SCHEDY_URL:-/schedy} - volumes: - - ./:/app - - /app/node_modules - command: >- - sh -c "apk add --no-cache python3 make g++ git libc6-compat - && export PYTHON=/usr/bin/python3 - && npm ci --legacy-peer-deps --no-audit --no-fund - && mkdir -p .next/static/development - && npm run dev -- --hostname 0.0.0.0 --port 3000" - ports: + # ports: - "3000:3000" restart: unless-stopped depends_on: diff --git a/next.config.ts b/next.config.ts index 2dcea95..8b6ebd6 100644 --- a/next.config.ts +++ b/next.config.ts @@ -5,6 +5,8 @@ const nextConfig: NextConfig = { eslint: { ignoreDuringBuilds: true, }, + // Produce a self-contained server bundle at .next/standalone + output: 'standalone', images: { remotePatterns: [ {