إنتقل إلى المحتوى الرئيسي

Vaults

يجمع التوكن الضريبي حصة من كل عملية شراء وبيع. تذهب تلك الحصة إلى مستلم رسوم (fee receiver). في إطلاق التوكن الضريبي العادي يكون مستلم الرسوم محفظة. في إطلاق vault يكون مستلم الرسوم عقدًا يُنشر عند الإطلاق، فتصل الإيرادات إلى مكان له قواعد: تقسيمها عبر محافظ، أو تدفقها إلى مستلم واحد، أو حجزها لهوية، أو أي شيء آخر يبرمجه مؤلف الـ vault.

هذه الصفحة موجّهة للمُكامِلين الذين يريدون الإطلاق بـ vault أو قراءة واحد. إذا كنت تريد كتابة vault خاص بك، راجع custom-vault.md.

المحتويات​

كيف تصل الإيرادات إلى vault​

   trader ──buy/sell──▶ tax token
│ collects tax on the transfer
▼
settles the tax ← permissionless; anyone can poke it
│ splits by the allocation you set at launch
┌──────────────┼───────────────┬───────────────┐
▼ ▼ ▼ ▼
fee receiver holders burn liquidity
(the vault) (dividends) (0xdead) (adds LP)

لا يدفع التوكن الإيرادات في كل صفقة. بل يتراكم عليه الضريبة ويسوّيها على دفعات. عندما يسوّي، تُرسَل حصة مستلم الرسوم إلى الـ vault. يسجّل الـ vault الخاص بك الإيرادات ويدفعها لاحقًا، عبر استدعاءات distribute() / claim() الخاصة به. هذا التجميع على دفعات هو سبب أن الـ vault يأخذ دائمًا شكل "تراكَم الآن، ادفع لاحقًا".

رسوم المنصة البالغة 10% على ضريبة المُنشئ في CheesePad هي رسم منفصل، وليست جزءًا من allocation الخاصة بك؛ راجع نموذج رسوم التوكن لكيفية ملاءمتها إلى جانب الضريبة.

تأتي حصص allocation الأربع من allocation التي تحددها في taxConfig عند الإطلاق، ويجب أن يساوي مجموعها 10000 BPS:

Sliceإلى أين تذهب
feeReceiverالـ vault
holdersحائزو التوكن، كأرباح (تحتاج minHolderShare غير صفرية)
burnالعنوان الميت
liquidityتُضاف مرة أخرى كسيولة LP

حتى يتلقى الـ vault أي دفعة، يجب أن تكون allocation.feeReceiver أعلى من صفر، وأن يكون جانب ضريبة واحد على الأقل غير صفري. يتحقق الـ launchpad من ذلك ويفشل الإطلاق خلاف ذلك.

الإطلاق بـ vault​

استخدم createMicroSaleTaxTokenWithVaultV2. فوق CreateParamsV2 المعتادة، تمرّر عنوان مصنع vault، وكتلة vaultData مُرمَّزة بـ ABI تضبط الـ vault المحدد، وdexKey الذي يسمّي الـ DEX المُراد الإدراج عليه.

function createMicroSaleTaxTokenWithVaultV2(
CreateParamsV2 calldata params, // same struct as the tax-token launch, incl. taxConfig
address vaultFactory, // a factory the platform trusts (see Factory addresses)
bytes calldata vaultData, // ABI-encoded config for this vault; shape depends on factory
address dexKey // the DEX to list on
) external payable returns (address fundManager);

ما يقوم به الـ launchpad، بالترتيب، وكلها بمبدأ الفشل الآمن (أي فشل يُلغي الإطلاق بأكمله):

  1. يؤكّد أن المصنع يشير إلى هذا الـ launchpad.
  2. يؤكّد أن المصنع يقبل توكن التسعير الخاص بالبيع.
  3. يؤكّد أن المصنع يفهم مراجعة بيانات الإطلاق الحالية.
  4. يستدعي دالة مراجعة المصنع مع معاملات إطلاقك؛ ويجب أن توافق.
  5. يجعل المصنع ينشر الـ vault.
  6. يؤكّد أن وضع إيرادات الـ vault يطابق توكن التسعير (راجع أدناه).
  7. يربط الـ vault كمستلم رسوم التوكن.

أنت لا توصّل أي شيء بنفسك أبدًا. إذا وافق المصنع، تحصل على توكن حيّ تتدفق ضريبته إلى vault جديد.

نفس التواصل يدعم توكن bonding curve ضريبي: createBondingCurveTaxTokenWithVaultV2 تأخذ vaultFactory وvaultData وdexKey وتجري الفحوص المتطابقة. القيد هو أن وضع إيرادات الـ vault يجب أن يطابق عملة تسعير المنحنى — الوضع الأصلي لمنحنى BNB، ووضع ERC20 لمنحنى مُسعَّر بـ ERC20 (راجع الإيرادات الأصلية مقابل ERC20). كل ما يلي ينطبق على نمطي الإطلاق كليهما.

ترميز vaultData​

vaultData معتمة بالنسبة للـ launchpad؛ كل مصنع يعرّف شكله الخاص. يعلن المصنع عن ذلك الشكل عبر vaultDataSchema()، حتى تتمكن واجهة المستخدم من بناء النموذج بشكل عام. للترميز يدويًا، اتبع ترتيب حقول المخطط وأنواعها. أمثلة ملموسة للـ vaultين المُقدَّمين موجودة أدناه.

استعادة عنوان الـ vault​

بعد الإطلاق، اقرأه من البيع:

const sale = await launchpad.getMicroSaleByFundManager(fundManager);
console.log("vault:", sale.vault); // the deployed vault
console.log("via factory:", sale.vaultFactory); // the factory that produced it

يسجّل البيع أيضًا أي مصنع أنتج الـ vault، فيمكن لقائمة سماح خارج السلسلة أن تضع شارة على الـ vaults التي جاءت من مصنع موثوق.

الإيرادات الأصلية مقابل ERC20​

يتعامل الـ vault مع الإيرادات بأصل واحد بالضبط، يُقرَّر عند الإطلاق:

  • الوضع الأصلي عندما يكون توكن التسعير الخاص بالبيع هو WBNB. تصل الإيرادات كـ BNB.
  • وضع ERC20 خلاف ذلك. تصل الإيرادات كتوكن التسعير، وتُرفض العملات الأصلية العابرة.

يؤكّد الـ launchpad أن وضع الـ vault يطابق توكن التسعير، فلا يمكن لمصنع غير متطابق أن يعطّل التداول. لإطلاق بعملة تسعير ERC20، يجمع المساهمون التمويل بتوكن التسعير ERC20 ذاك — راجع microsale.md. يأتي توكن التسعير من ارتباط القالب، لذا فإن إطلاقًا بمستلم-محفظة أو بلا ضريبة مقابل قالب مرتبط بـ ERC20 يجمع التمويل بتوكن التسعير ذاك كذلك؛ الفرق مع vault هو فقط في المكان الذي تصل إليه حصة مستلم الرسوم.

الـ vaults التي تقدّمها CheesePad​

vaultان جاهزان، لكلٍّ منهما مصنعه الخاص. توجّه createMicroSaleTaxTokenWithVaultV2 إلى المصنع وتمرّر vaultData المطابق.

SplitterVault: مستفيدون ثابتون حسب الحصة​

يقسّم الإيرادات عبر قائمة ثابتة من المحافظ بنقاط الأساس. حتى 50 مستفيدًا، ويجب أن يساوي مجموع الحصص 10000، بلا تكرار، وبلا عناوين صفرية.

vaultData هي abi.encode(address[] payees, uint16[] bps):

const payees = ["0xAaa...", "0xBbb..."];
const bps = [7000, 3000]; // 70% / 30%; must sum to 10000

const vaultData = ethers.AbiCoder.defaultAbiCoder().encode(
["address[]", "uint16[]"],
[payees, bps]
);

await launchpadRW.createMicroSaleTaxTokenWithVaultV2(params, SPLITTER_FACTORY, vaultData, dexKey, {
value: creationFee,
});

استخدام الـ vault بعد الإطلاق:

  • distribute() مفتوحة بلا إذن. تُقيّد حصة كل مستفيد من الرصيد المتراكم وتدفعها إليه. إذا تعذّر على مستفيد الاستلام (عقد يفشل تنفيذه، مثلًا)، تُحفظ حصته كـ owed ليسحبها لاحقًا، ويظل الآخرون يتقاضون.
  • claim() تتيح للمستفيد سحب رصيده owed الخاص.
  • splitConfig() تُرجع المستفيدين وحصصهم بنقاط الأساس؛ وowed(address) تُرجع الرصيد المعلّق لمستفيد؛ وcredited() تُرجع الإجمالي الجاري المُقيَّد.

يقبل SplitterVault أي توكن تسعير.

GiftVault: التدفق إلى المحفظة خلف حساب X​

يحتفظ بإيرادات توكن للشخص خلف حساب X (تويتر). لا يُدفع لأحد حتى تُربط محفظة بالحساب، والربط مُصرَّح به بواسطة توقيع مُرحِّل (relayer) من المنصة، فلا يمكن إلا للمالك الحقيقي للحساب أن يطالب.

vaultData هي abi.encode(string xHandle, uint256 timeoutPeriod):

const vaultData = ethers.AbiCoder.defaultAbiCoder().encode(
["string", "uint256"],
["cheesepad", 30n * 24n * 60n * 60n] // handle, and 30-day bind window
);

await launchpadRW.createMicroSaleTaxTokenWithVaultV2(params, GIFT_FACTORY, vaultData, dexKey, {
value: creationFee,
});

timeoutPeriod بين يوم واحد و365 يومًا. يتطلب مصنع GiftVault أيضًا أن تكون allocation.holders أعلى من صفر، بسبب الحل الاحتياطي أدناه.

كيف تسير الأمور:

  • الربط. يحصل مالك المحفظة على إثبات موقّع من المُرحِّل (توقيع EIP-712 على الحساب، والتوكن، ومحفظة المستفيد، وnonce، وتاريخ انتهاء) ويستدعي bindBeneficiary(beneficiary, nonce, validUntil, signature). من تلك اللحظة، تتدفق الإيرادات إلى تلك المحفظة. يكون الربط مفتوحًا فقط حتى انتهاء المهلة، وفقط عندما يتحقق الإثبات.
  • السحب. بعد الربط، تدفع distribute() الإيرادات المتراكمة إلى المستفيد، وتتيح له claim() سحبها.
  • القفل. يمكن للمستفيد استدعاء lock() لإقصاء المُرحِّل والمنصة عن أي إعادة ربط مستقبلية.
  • الإنقاذ. قبل انتهاء المهلة وقبل القفل، يمكن لدعامة المنصة الاحتياطية تصحيح محفظة مربوطة خطأً. وهي لا تعيد توجيه إلا الإيرادات المستقبلية.
  • الحل الاحتياطي بالأرباح. إذا لم يربط أحد قبل انتهاء المهلة، يمكن لأي شخص استدعاء distributeDividend()، التي توجّه الإيرادات غير المُطالَب بها إلى حائزي التوكن كأرباح. لهذا يصرّ المصنع على حصة حائزين. بمجرد إطلاقها، يبقى الـ vault بشكل دائم في وضع الأرباح ويُغلَق الربط.

قراءة vault بشكل عام​

يصف كل vault حقول قراءته وإجراءاته الخاصة عبر vaultUISchema(). يمكن لواجهة مستخدم عرض vault لم ترَه من قبل: تقرأ المخطط، وتستدعي كل دالة قراءة، وتفك ترميز النتيجة باستخدام الأنواع المُعلَنة. الشكل المشترك:

const vault = new ethers.Contract(sale.vault, VaultABI, provider);

const isNative = await vault.isNativeRevenue(); // true = BNB, false = ERC20
const quote = await vault.quoteToken(); // revenue asset
const desc = await vault.description(); // one-liner for listings
const schema = await vault.vaultUISchema(); // methods to render (reads + writes)

تُرجع vaultUISchema() قيمة vaultType، وdescription، وقائمة من الدوال. كل دالة إما حقل قراءة (تستدعيها واجهة المستخدم وتعرض النتيجة المُصنَّفة) أو إجراء كتابة (تعرض واجهة المستخدم زرًا ونموذج إدخال، بالإضافة إلى أي موافقات ERC20 تحتاجها أولًا). أنواع المخطط مشروحة في custom-vault.md وevents-and-data.md.

الجزء المهم لقارئ عام: لا يكشف الـ vault إلا ما يعلنه مخططه. لا يوجد استبطان تلقائي للتخزين، لذا ثق بالمخطط بوصفه قائمة كل ما يستحق العرض.

عناوين المصانع​

VaultNetworkFactory
SplitterVaultBNB (56)0x9d04B0Bfe281411d4A01a69BD89f7Ba6b7F5A59b
SplitterVaultBNB testnet (97)0xbB5165684832a8Cda1121081EBb168ca6636abc6
SplitterVaultRobinhood (4663)0x58DBab8C3529492c12Ee913313Cf600f522a39D9
GiftVaultBNB (56)0xFa36D3e2240BEDB22bad35D8FD4165AAf0598896
GiftVaultBNB testnet (97)0x8227F4330E3aa43c94b9fDc409D71A6C6C2033B7
GiftVaultRobinhood (4663)0x7FD34AeA57250aC66C59448339316aF745f6B9ef

المصنع عديم الحالة وغير قابل للتغيير. الإصدار الجديد هو عنوان جديد، لذا أكّد العنوان الحالي مع فريق CheesePad قبل أتمتة الإطلاقات مقابله.