Skip to content
Merged
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
10 changes: 2 additions & 8 deletions backend/alembic/versions/p6q7r8s9t0u1_referral_campaign.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ def upgrade() -> None:
"CREATE INDEX IF NOT EXISTS idx_rc_referree_month "
"ON referral_campaigns (referree_id, reward_start_month, reward_expires_month)"
)
op.execute(
"CREATE INDEX IF NOT EXISTS idx_rc_partner "
"ON referral_campaigns (partner_id)"
)
op.execute("CREATE INDEX IF NOT EXISTS idx_rc_partner ON referral_campaigns (partner_id)")

op.execute("""
CREATE TABLE IF NOT EXISTS uat_wallet_ledger (
Expand All @@ -64,10 +61,7 @@ def upgrade() -> None:
"ON uat_wallet_ledger (reference_fee_tx_id, entry_type, reason) "
"WHERE reference_fee_tx_id IS NOT NULL"
)
op.execute(
"CREATE INDEX IF NOT EXISTS idx_uwl_month "
"ON uat_wallet_ledger (month)"
)
op.execute("CREATE INDEX IF NOT EXISTS idx_uwl_month ON uat_wallet_ledger (month)")
else:
# SQLite (テスト環境)
op.create_table(
Expand Down
3 changes: 1 addition & 2 deletions backend/app/aave/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1193,8 +1193,7 @@ def make_aave_client(
# build_deposit_txs / build_withdraw_tx が "Unknown asset" で失敗する (method2 バグ修正)。
if token_addresses and not hasattr(client, "token_addresses"):
client.token_addresses = {
sym: Web3.to_checksum_address(addr)
for sym, addr in token_addresses.items()
sym: Web3.to_checksum_address(addr) for sym, addr in token_addresses.items()
}
return client
raise ValueError(f"不明な AAVE_CLIENT_TYPE: {client_type!r} (dummy | web3)")
Expand Down
4 changes: 1 addition & 3 deletions backend/app/api/v1/fees.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,9 +443,7 @@ def finalize_month_core(
# --- UAT ウォレット台帳 記録 (冪等: 同月再実行でも重複しない) ---
fee_txs_this_month = (
db.execute(
select(FeeTransaction).where(
FeeTransaction.calculation_month == month_start
)
select(FeeTransaction).where(FeeTransaction.calculation_month == month_start)
)
.scalars()
.all()
Expand Down
2 changes: 1 addition & 1 deletion backend/app/auth/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from sqlalchemy.orm import Session

from app.database import get_db
from app.referral import service as referral_service

from .dependencies import require_active_user
from .models import (
Expand Down Expand Up @@ -54,7 +55,6 @@
WalletLinkResponse,
)
from .service import AuthService
from app.referral import service as referral_service

limiter = Limiter(key_func=get_remote_address)

Expand Down
2 changes: 1 addition & 1 deletion backend/app/automation/ai_judgment_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
from sqlalchemy import func, select
from sqlalchemy.orm import Session

from app.aave.gas_estimator import estimate_static_gas_cost_usd
from app.ai.judgment_log import get_judgment_logger
from app.ai.models import AIDecision, AiDecisionFeature
from app.ai.schemas import CrossValidationResult, RAGContext, TradeAction
from app.ai.service import AIService
from app.auth.constants import ExecutionPolicy
from app.auth.models import InvestmentTier, User, normalize_tier
from app.aave.gas_estimator import estimate_static_gas_cost_usd
from app.automation.aave_data_fetcher import AaveMarketData, fetch_aave_market_data_safe
from app.data_feeds.context import MarketContext, build_market_context
from app.database import SessionLocal
Expand Down
2 changes: 1 addition & 1 deletion backend/app/referral/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def _add_months(d: date, months: int) -> date:
return date(year, month, 1)


def get_referral_earnings(db: Session, partner_id: int) -> dict:
def get_referral_earnings(db: Session, partner_id: int) -> dict[str, str | int | None]:
"""紹介キャンペーン収益サマリーを返す。

- referral_count: referrer_id == partner_id のユーザー数
Expand Down
4 changes: 4 additions & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ pytest-asyncio>=0.23.0
web3>=6.15.1
eth-account>=0.11.0
python-dotenv>=1.0.0
# aiohttp は web3/ccxt 経由の transitive dep。3.14.0 で AsyncStreamReaderMixin が
# 削除され、vcrpy(<=8.1.1) のテスト記録が壊れる (upstream Issue #995 / PR #996 未リリース)。
# 上流が対応するまで <3.14 に固定し、CI と prod で同一版を保証する。
aiohttp<3.14

# Authentication & Database (Phase 12)
sqlalchemy>=2.0.0
Expand Down
4 changes: 4 additions & 0 deletions backend/tests/reports/test_monthly_report_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ def client(test_db) -> TestClient:


def _register_admin(client: TestClient) -> str:
# フルスイート実行時、他テスト (test_risk_mode.py / test_e2e_approve_flow.py 等) が
# fixture 実行時に INITIAL_ADMIN_EMAIL を上書きするため、register 直前に再セットする。
# これを怠ると /auth/register が email 不一致で 403 を返す (module-level の set では不足)。
os.environ["INITIAL_ADMIN_EMAIL"] = _ADMIN_EMAIL
client.post(
"/auth/register",
json={"email": _ADMIN_EMAIL, "username": "admin_report", "password": _ADMIN_PASSWORD},
Expand Down
14 changes: 12 additions & 2 deletions backend/tests/test_cryptact_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,15 @@ def test_csv_header_row(self, client_with_proposals: TestClient) -> None:
content = r.content.decode("utf-8-sig")
reader = csv.DictReader(io.StringIO(content))
assert reader.fieldnames == [
"Timestamp", "Action", "Source", "Base", "Volume", "Price", "Counter", "Fee", "FeeCcy"
"Timestamp",
"Action",
"Source",
"Base",
"Volume",
"Price",
"Counter",
"Fee",
"FeeCcy",
]

def test_only_executed_proposals_included(self, client_with_proposals: TestClient) -> None:
Expand All @@ -161,7 +169,9 @@ def test_supply_maps_to_lending(self, client_with_proposals: TestClient) -> None
content = r.content.decode("utf-8-sig")
reader = csv.DictReader(io.StringIO(content))
rows = list(reader)
supply_row = next(row for row in rows if row["Base"] == "USDC" and row["Action"] == "LENDING")
supply_row = next(
row for row in rows if row["Base"] == "USDC" and row["Action"] == "LENDING"
)
assert supply_row["Action"] == "LENDING"
assert supply_row["Source"] == "AAVE_V3"
assert supply_row["Counter"] == "USD"
Expand Down
3 changes: 2 additions & 1 deletion backend/tests/test_fee_transfer_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,8 @@ def test_fee_usd_calculation(fee_jpy, sub_jpy, excess_jpy, rate, expected_usd):
# Lane R: transfer_service / AllowanceService (EIP-2612 新インタフェース)
# ===========================================================================

from app.fees.transfer_service import FeeTransferResult, FeeTransferService as NewFeeTransferService # noqa: E402
from app.fees.transfer_service import FeeTransferResult # noqa: E402
from app.fees.transfer_service import FeeTransferService as NewFeeTransferService # noqa: E402


class TestFeeTransferServiceDisabled:
Expand Down
14 changes: 12 additions & 2 deletions backend/tests/test_gas_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,12 @@ def test_supply_uses_supply_fallback_gas(self) -> None:
"SUPPLY", eth_usd_price=eth_price, gas_price_wei=Decimal("20000000000")
)
# 300000 * 20 Gwei = 0.006 ETH * $2000 = $12.00
expected = Decimal(str(DEFAULT_FALLBACK_GAS_SUPPLY)) * Decimal("20000000000") / Decimal("1e18") * eth_price
expected = (
Decimal(str(DEFAULT_FALLBACK_GAS_SUPPLY))
* Decimal("20000000000")
/ Decimal("1e18")
* eth_price
)
assert cost == expected

def test_withdraw_uses_withdraw_fallback_gas(self) -> None:
Expand All @@ -137,7 +142,12 @@ def test_withdraw_uses_withdraw_fallback_gas(self) -> None:
cost = estimate_static_gas_cost_usd(
"WITHDRAW", eth_usd_price=eth_price, gas_price_wei=Decimal("20000000000")
)
expected = Decimal(str(DEFAULT_FALLBACK_GAS_WITHDRAW)) * Decimal("20000000000") / Decimal("1e18") * eth_price
expected = (
Decimal(str(DEFAULT_FALLBACK_GAS_WITHDRAW))
* Decimal("20000000000")
/ Decimal("1e18")
* eth_price
)
assert cost == expected

def test_uses_fallback_eth_price_when_none(self) -> None:
Expand Down
1 change: 0 additions & 1 deletion backend/tests/test_line_messaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
build_monthly_report_flex_bubble,
)


# ── build_monthly_report_flex_bubble ──────────────────────────────────────────


Expand Down
11 changes: 11 additions & 0 deletions docs/integration/backend_deps.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,17 @@

## backend/requirements.txt

### 変更 #3: aiohttp<3.14 固定(vcrpy 非互換 / CI green 回復)(PR #529 / 2026-06-04)
- **コミット範囲**: `a300118` (fix/main-ci-green)
- **変更内容**: `aiohttp<3.14` を requirements.txt に追加
- **理由**: aiohttp 3.14.0 で `AsyncStreamReaderMixin` が削除され、vcrpy<=8.1.1 の cassette 再生が
`ERROR` になり CI の `test_judge_with_rag_vcr` が2件 failing(upstream Issue #995 / PR #996 未リリース)。
aiohttp は web3/ccxt 経由の transitive **runtime** dep のため requirements.txt 側で pin し、
CI と prod で同一版(3.13.x)を保証。upstream が対応次第 (`vcrpy>8.1.1` + `aiohttp>=3.14`) に更新する。
- **影響範囲**: aiohttp の upper cap 追加のみ。web3 (`>=3.7.4`) / ccxt (`>=3.10.11`) との両立を
`pip check` で確認済み。アプリケーションロジックへの影響なし。
- **承認**: fix/main-ci-green → main (PR #529)

### 変更 #2: PyJWT[crypto] extra 追加(Privy ID Token 検証対応)(PR #155 / 2026-04-27)
- **コミット範囲**: `c88dfd2` – `41f77d7` (feature/privy-did-storage)
- **変更内容**: `PyJWT>=2.9.0` → `PyJWT[crypto]>=2.9.0`
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ module = [
"tiktoken.*",
"jose.*",
"feedparser.*",
"reportlab.*",
]
ignore_missing_imports = true

Expand Down
Loading