Chuyển tới nội dung chính

Vaults

Một tax token thu một slice của mỗi lệnh mua và bán. Slice đó đi tới một fee receiver. Trong đợt launch tax-token thông thường, fee receiver là một ví. Trong một launch dùng vault, fee receiver là một contract được deploy tại thời điểm launch, nên doanh thu đến một nơi có luật lệ: chia nó cho nhiều ví, stream nó tới một người nhận, giữ nó cho một danh tính, hoặc bất cứ điều gì khác mà tác giả vault code ra.

Trang này dành cho các bên tích hợp muốn launch với một vault hoặc đọc một vault. Nếu bạn muốn viết vault của riêng mình, xem custom-vault.md.

Mục lục​

Cách doanh thu đến một 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)

Token không đẩy doanh thu ở mỗi giao dịch. Nó tích lũy thuế và settle theo từng đợt. Khi settle, slice fee receiver được gửi tới vault. Vault của bạn ghi nhận doanh thu và trả nó ra sau, trên các lệnh gọi distribute() / claim() của chính nó. Việc gom theo đợt này là lý do một vault luôn có hình dạng "tích lũy ngay, trả sau."

Khoản phí platform 10% của CheesePad trên creator tax là một khoản phí tách biệt, không phải một phần của allocation của bạn; xem mô hình phí token để biết nó phù hợp thế nào bên cạnh thuế.

Bốn slice allocation đến từ allocation bạn đặt trong taxConfig lúc launch, và chúng phải cộng lại bằng 10000 BPS:

SliceNó đi đâu
feeReceivervault
holderstoken holder, dưới dạng dividend (cần một minHolderShare khác không)
burnđịa chỉ dead
liquidityđược thêm lại làm LP

Để một vault từng được trả, allocation.feeReceiver phải lớn hơn không và ít nhất một bên thuế phải khác không. Launchpad kiểm tra điều này và revert launch nếu không.

Launch với một vault​

Dùng createMicroSaleTaxTokenWithVaultV2. Trên CreateParamsV2 thông thường, bạn truyền vào một địa chỉ vault factory, một blob vaultData đã được ABI-encode để cấu hình vault cụ thể, và dexKey đặt tên DEX để list.

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 làm gì, theo thứ tự, tất cả fail-closed (bất kỳ thất bại nào cũng revert toàn bộ launch):

  1. Xác nhận factory trỏ tới launchpad này.
  2. Xác nhận factory chấp nhận quote token của sale.
  3. Xác nhận factory hiểu revision launch-data hiện tại.
  4. Gọi review hook của factory với các tham số launch của bạn; nó phải approve.
  5. Cho factory deploy vault.
  6. Xác nhận revenue mode của vault khớp với quote token (xem bên dưới).
  7. Gắn vault làm fee receiver của token.

Bạn không bao giờ tự đấu nối gì cả. Nếu factory approve, bạn có một token đang chạy với thuế chảy vào một vault mới.

Cùng handshake đó hậu thuẫn một bonding curve tax token: createBondingCurveTaxTokenWithVaultV2 nhận một vaultFactory, vaultData, và dexKey và chạy các kiểm tra giống hệt. Ràng buộc là revenue mode của vault phải khớp với đồng tiền quote của curve — native mode cho một curve BNB, ERC20 mode cho một curve được định giá bằng một quote token ERC20 (xem Doanh thu native vs ERC20). Mọi thứ bên dưới áp dụng cho cả hai kiểu launch.

Encode vaultData​

vaultData là opaque đối với launchpad; mỗi factory tự định nghĩa hình dạng của nó. Một factory công bố hình dạng đó qua vaultDataSchema(), nên một UI có thể build form một cách tổng quát. Để encode bằng tay, hãy theo thứ tự trường và kiểu của schema. Các ví dụ cụ thể cho hai vault được cung cấp nằm bên dưới.

Lấy lại địa chỉ vault​

Sau khi launch, đọc nó từ sale:

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

Sale cũng ghi lại factory nào đã tạo ra vault, nên một allowlist off-chain có thể gắn nhãn cho các vault đến từ một factory đáng tin cậy.

Doanh thu native vs ERC20​

Một vault xử lý doanh thu bằng đúng một tài sản, được quyết định lúc launch:

  • Native mode khi quote token của sale là WBNB. Doanh thu đến dưới dạng BNB.
  • ERC20 mode trong các trường hợp khác. Doanh thu đến dưới dạng quote token, và các đồng coin native lạc bị từ chối.

Launchpad khẳng định rằng mode của vault khớp với quote token, nên một factory không khớp không thể brick việc giao dịch. Với một launch được định giá bằng ERC20, contributor raise bằng chính quote token ERC20 đó — xem microsale.md. Quote token đến từ ràng buộc của template, nên một launch fee-receiver ví hoặc không thuế dựa trên một template gắn với một quote token ERC20 cũng raise bằng chính quote token đó; điểm khác biệt với một vault chỉ là nơi slice fee-receiver đến.

Các vault CheesePad cung cấp​

Hai vault làm sẵn, mỗi vault có factory riêng. Bạn trỏ createMicroSaleTaxTokenWithVaultV2 tới factory và truyền vaultData tương ứng.

SplitterVault: các payee cố định theo tỷ lệ​

Chia doanh thu cho một danh sách ví cố định theo basis point. Tối đa 50 payee, các share phải cộng lại bằng 10000, không trùng lặp, không địa chỉ không.

vaultData là 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,
});

Dùng vault sau khi launch:

  • distribute() là permissionless. Nó ghi có share của mỗi payee từ số dư đã tích lũy và đẩy nó tới họ. Nếu một payee không thể nhận (một contract bị revert, chẳng hạn), share của họ được giữ lại làm owed để họ pull sau, và những người khác vẫn được trả.
  • claim() cho phép một payee pull số dư owed của chính mình.
  • splitConfig() trả về các payee và bps của họ; owed(address) trả về số dư đang chờ của một payee; credited() trả về tổng cộng đang chạy đã được ghi có.

SplitterVault chấp nhận bất kỳ quote token nào.

GiftVault: stream tới ví đứng sau một X handle​

Giữ doanh thu của một token cho người đứng sau một X (Twitter) handle. Không ai được trả cho tới khi một ví được bind với handle, và việc bind được ủy quyền bởi một chữ ký relayer của platform, nên chỉ chủ thực sự của handle mới có thể claim.

vaultData là 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 nằm giữa 1 và 365 ngày. Factory của GiftVault cũng yêu cầu allocation.holders lớn hơn không, vì cơ chế fallback bên dưới.

Nó diễn ra thế nào:

  • Bind. Chủ ví lấy một bằng chứng được relayer ký (một chữ ký EIP-712 trên handle, token, ví beneficiary, một nonce, và một expiry) và gọi bindBeneficiary(beneficiary, nonce, validUntil, signature). Từ đó trở đi, doanh thu stream tới ví đó. Việc bind chỉ mở cho tới timeout, và chỉ một khi bằng chứng được kiểm chứng.
  • Withdraw. Sau khi bind, distribute() đẩy doanh thu đã tích lũy tới beneficiary, và claim() cho phép họ pull nó.
  • Lock. Beneficiary có thể gọi lock() để cắt relayer và platform ra khỏi bất kỳ lần rebind nào trong tương lai.
  • Rescue. Trước timeout và trước một lock, backstop của platform có thể sửa một ví bị bind sai. Nó chỉ định tuyến lại doanh thu trong tương lai.
  • Dividend fallback. Nếu không ai bind trước timeout, bất kỳ ai cũng có thể gọi distributeDividend(), thứ định tuyến doanh thu chưa được claim tới các holder của token dưới dạng dividend. Đây là lý do factory nhất quyết đòi một slice holder. Một khi nó kích hoạt, vault vĩnh viễn ở chế độ dividend và việc bind bị đóng.

Đọc một vault một cách tổng quát​

Mỗi vault mô tả các trường đọc và các hành động của chính nó qua vaultUISchema(). Một UI có thể render một vault nó chưa từng thấy: nó đọc schema, gọi từng phương thức đọc, và giải mã kết quả bằng các kiểu đã khai báo. Hình dạng chung:

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() trả về một vaultType, một description, và một danh sách phương thức. Mỗi phương thức hoặc là một trường đọc (UI gọi nó và hiển thị kết quả có kiểu) hoặc một hành động ghi (UI render một nút và một form nhập, cộng với bất kỳ ERC20 approval nào nó cần trước). Các kiểu schema được nói tới trong custom-vault.md và events-and-data.md.

Phần quan trọng cho một reader tổng quát: một vault chỉ phơi ra những gì schema của nó khai báo. Không có introspection storage tự động, nên hãy tin schema như danh sách của mọi thứ đáng hiển thị.

Địa chỉ factory​

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

Một factory là stateless và immutable. Một phiên bản mới là một địa chỉ mới, nên hãy xác nhận địa chỉ hiện tại với đội ngũ CheesePad trước khi bạn tự động hóa các launch dựa trên nó.