پرش به مطلب اصلی

مرحله ۱: لینک‌های پرداخت مبتنی بر قرارداد روی EVM

· خواندن 6 دقیقه
OrcaRail
Crypto payment rails for web2 apps

۲۰ آوریل ۲۰۲۶ — مرحله ۱ شروع واقعی کار مهندسی نقشه راه غیرامانی است. EOAهای مشتق از HD برای هر لینک و smart accountهای آلکمی را با الگوی کارخانه + گیرنده به‌شکل کلون حداقلی روی EVM جایگزین می‌کنیم. وجوه در همان تراکنش پرداخت به‌صورت اتمیک تقسیم می‌شوند؛ بدون جاروب و بدون امانت‌داری.

خلاصه​

  • PaymentLinkFactory.computeAddress(linkId) یک آدرس قطعی CREATE2 برمی‌گرداند. این آدرس را پیش از استقرار هر چیزی به پرداخت‌کننده نشان می‌دهیم.
  • PaymentLinkReceiver یک کلون حداقلی EIP-1167 است. توکن بومی یا ERC-20 می‌پذیرد، رویداد Paid منتشر می‌کند و در همان تراکنش FeeSplitter.split() را فراخوانی می‌کند.
  • api/src/payments/wallet.service.ts دیگر برای لینک‌های EVM کیف پول HD نمی‌سازد؛ به‌جای آن تابع view کارخانه را صدا می‌زند.
  • مسیر جاروب (drainSmartAccountWallet، getSmartAccountClientForDepositWallet) برای لینک‌هایی که با پرچم useOnChainReceiver ساخته شده‌اند دور زده می‌شود.

این مرحله چه چیزی را تغییر می‌دهد​

در سمت «بعد» هیچ جعبه‌ای که ما کنترل کنیم وجوه را نگه نمی‌دارد.

قراردادهای معرفی‌شده​

همه در یک پکیج جدید به نام contracts/evm/.

PaymentLinkFactory​

  • computeAddress(bytes32 linkId) view returns (address) — آدرس قطعی CREATE2 مشتق از linkId (همان UUID فعلی لینک پرداخت که به bytes32 هش شده است).
  • deployAndPay(bytes32 linkId, Split split, address token, uint256 amount) — استقرار تنبل + پرداخت در یک تراکنش. کارخانه پیاده‌سازی PaymentLinkReceiver را کلون می‌کند، آن را با Split مقداردهی می‌کند و وجوه را ارسال می‌کند.
  • isDeployed(bytes32 linkId) view returns (bool) — تابع کمکی که ایندکسر و رابط کاربری از آن استفاده می‌کنند.
  • قابل ارتقا پشت proxy نوع UUPS، متعلق به مولتی‌سیگ استقرار (Safe سه از پنج)، با timelock چهل‌وهشت ساعته روی upgradeTo.

PaymentLinkReceiver (کلون)​

  • پس از مقداردهی تغییرناپذیر است. struct مربوط به Split و آدرس FeeSplitter را ذخیره می‌کند.
  • pay(address token, uint256 amount) — توکن بومی و ERC-20 را در یک نقطه ورود مدیریت می‌کند. از SafeERC20 استفاده می‌کند تا توکن‌های غیراستاندارد (USDT) هم کار کنند. رویداد Paid(linkId, payer, token, amount) را منتشر می‌کند.
  • FeeSplitter.split() را به‌صورت اتمیک فراخوانی می‌کند. اگر تقسیم revert شود، پرداخت هم revert می‌شود.
  • تابع صریح refund(bytes32 txId) که فقط EOA مربوط به keeper فروشنده یا مولتی‌سیگ استقرار می‌تواند فراخوانی کند.

FeeSplitter​

  • split(Split s, address token, uint256 amount) — بر اساس واحد پایه توزیع می‌کند. wei باقی‌مانده به فروشنده می‌رسد (بدون هدر رفتن خرده‌ها).
  • رویداد Split(txId, merchant, platform, referral, bridgeFee) را منتشر می‌کند تا ایندکسر با payloadهای وب‌هوک قدیمی هم‌خوان بماند.

تغییرات API​

بزرگ‌ترین تغییر کد در api/src/payments/wallet.service.ts است. امروز getOrCreateAddressForPaymentLink از hd_wallet_seed مشتق‌گیری می‌کند، آدرس counterfactual آلکمی را محاسبه می‌کند و در wallet_address ذخیره می‌کند. پس از مرحله ۱، برای زنجیره‌های EVM که پرچم فعال دارند، این تابع چنین می‌شود:

async function getOrCreateAddressForPaymentLink(paymentLinkId, network) {
if (isEvm(network) && featureFlags.useOnChainReceiver(network.chainId)) {
const address = await factory.computeAddress(hashLinkId(paymentLinkId))
return { address, walletAddressId: null, derivationPath: null }
}
// legacy path unchanged
}

بدون مشتق‌گیری HD. بدون هیچ داده خصوصی در پایگاه داده برای لینک‌های جدید.

یک سرویس جدید به نام payments/indexer/evm-paid-event.service.ts با viem.watchContractEvent روی هر زنجیره فعال مشترک رویدادهای Paid می‌شود. هنگام تطابق:

  1. paymentLinkId را از رویداد (ایندکس‌شده به‌صورت bytes32) پیدا می‌کند.
  2. یک ردیف PaymentTransaction درج یا به‌روزرسانی می‌کند؛ با همان ساختار امروز.
  3. همان وب‌هوک‌هایی را منتشر می‌کند که امروز مسیر تکمیل جاروب منتشر می‌کند (api/src/webhooks/webhooks.service.ts).

پرچم useOnChainReceiver برای هر chain id جداگانه تعریف می‌شود. لینکی که در زمان خاموش بودن پرچم ساخته شود، برای همیشه روی مسیر جاروب قدیمی می‌ماند؛ لینک‌های در جریان را مهاجرت نمی‌دهیم.

موارد منسوخ‌شده​

در این مرحله این موارد را دور می‌زنیم اما حذف نمی‌کنیم:

  • SmartAccountWalletService.drainSmartAccountWallet — برای زنجیره‌هایی که پرچم فعال دارند دیگر فراخوانی نمی‌شود.
  • SmartAccountWalletService.getSmartAccountClientForDepositWallet — وقتی آدرس‌ها از کارخانه می‌آیند لازم نیست.
  • ردیف‌های wallet_address — برای زنجیره‌های EVM با پرچم فعال نوشته نمی‌شوند.

حذف واقعی در مرحله ۷ انجام می‌شود؛ پس از تسویه همه لینک‌های قدیمی روی آن زنجیره.

برنامه مهاجرت​

  • لینک‌های جدید روی Base: یک آدرس CREATE2 محاسبه‌شده توسط کارخانه می‌گیرند. رابط کاربری آن را مثل امروز نمایش می‌دهد.
  • لینک‌های باز فعلی روی Base: تا انقضا یا تسویه روی مسیر جاروب قدیمی می‌مانند. مهاجرت اجباری در کار نیست.
  • دیگر زنجیره‌های EVM: تا وقتی مرحله ۳ پرچمشان را روشن کند، روی مسیر قدیمی‌اند.

ریسک‌ها و راهکارها​

  • نمایش آدرس CREATE2 پیش از وجود هر کدی. راهکار: مستند کنیم که قابلیت بازیابی به استقراردهنده کارخانه بستگی دارد. سقف maxLinkValue در کارخانه برای ۳۰ روز اول.
  • USDT و دیگر توکن‌های ERC-20 غیراستاندارد. راهکار: SafeERC20 در هر دو قرارداد PaymentLinkReceiver و FeeSplitter؛ آزمون‌های fuzz در Foundry روی فورک mainnet با USDT.
  • توکن‌هایی که هنگام انتقال کارمزد کم می‌کنند. راهکار: فهرست مجاز توکن‌ها؛ توکن‌های خارج از آن به مسیر قدیمی برمی‌گردند.
  • تأخیر ایندکسر زنجیره. راهکار: اشتراک دوگانه (آلکمی + RPC عمومی پشتیبان)؛ کارهای تطبیق هر ساعت؛ درج/به‌روزرسانی idempotent.
  • یافته حسابرسی در حین توسعه. راهکار: حسابرسی پیش‌شرط است؛ پیش از گزارش رفع همه موارد، استقرار روی mainnet انجام نمی‌شود.

چک‌لیست وضعیت​

  • ساخت پروژه Foundry در contracts/evm/
  • پیاده‌سازی PaymentLinkFactory + PaymentLinkReceiver + FeeSplitter
  • آزمون‌های fuzz + invariant برای محاسبات تقسیم (فروشنده همیشه ≥ مبلغ مورد انتظار منهای کارمزد دریافت می‌کند)
  • قبولی آزمون‌های فورک برای USDT / ERC-20 غیراستاندارد
  • اتصال پرچم useOnChainReceiver در api/src/payments
  • انتشار ایندکسر evm-paid-event.service.ts و ارسال وب‌هوک‌های موجود
  • شروع حسابرسی و اعمال اصلاحات
  • استقرار روی Base mainnet از مولتی‌سیگ
  • گروه آزمایشی (canary) از فروشندگان با پرچم فعال

قدم بعدی​

با رفتن فروشندگان Base به گیرنده‌های قراردادی، مرحله ۲ همین کار را برای اشتراک‌ها انجام می‌دهد: اشتراک مبتنی بر allowance.


مستندات مرجع: وضعیت مرحله ۱ · مرجع قراردادها · معماری