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

Microsales

Địa chỉ contract

Microsale không có contract riêng. Chúng dùng chung một địa chỉ launchpad với pools và Melt Pools — một địa chỉ cho mỗi chain, một ABI, cả ba kiểu launch.

NetworkChain IDLaunchpad
BNB Chain (mainnet)560xD9CcE715619fA9082d21375B6B37A3a0d99138F4
BNB Chain (testnet)970x0AA21d47b600B04527c09BbD9A30aF32cb64f6cF
Robinhood Chain46630x7E0752B42f9db92F12E221E10fFfa10bfE8668C6

Một microsale cụ thể được nhận diện bằng địa chỉ fundManager của nó, thứ bạn truyền vào làm tham số cho các lệnh gọi bên dưới. Đó là một handle riêng cho từng sale, không phải một contract bạn gọi tới.

Microsale là một đợt bán token theo giá cố định. Bạn chọn một config template, launchpad mint ra một token mới, contributor gửi tiền cho tới khi chạm hard cap, và khi finalize launchpad list token bằng cách thêm liquidity vào một DEX. Mỗi microsale tạo ra đúng một token, và một token chỉ có thể được launch qua microsale đúng một lần.

Trang này đi qua toàn bộ vòng đời: chọn template, tạo sale, contribute, finalize, claim, và xử lý refund. Các launch dùng vault có trang riêng, vaults.md, nhưng lệnh create cũng được tóm tắt ở đây.

Mục lục​

Các thành phần​

  • Config (template). Platform công bố các template dùng lại được, cố định phần kinh tế: bao nhiêu token vào presale, bao nhiêu vào liquidity, hard cap, và thời lượng sale. Bạn launch dựa trên một template thông qua configId của nó.
  • Sale. Một instance được tạo từ một template. Được nhận diện bằng địa chỉ fundManager.
  • Token. Được mint tại thời điểm tạo sale. Tổng cung cố định ở mức 1,000,000,000 (1e27 với 18 decimal) và được chia giữa presale và LP theo template.
  • Fund manager. Một địa chỉ riêng cho từng sale, giữ số tiền raise và token cho tới khi finalize. Bạn không bao giờ gọi trực tiếp vào nó. Đây là handle bạn truyền vào hầu hết các hàm microsale, và các event quan trọng đều được index theo nó.

Trạng thái sale​

Một microsale luôn ở một trong ba trạng thái:

Trạng tháiGiá trịÝ nghĩa
Active0Đang mở để contribute
Finalized1Đã chạm hard cap, đã thêm liquidity, token có thể claim
Cancelled2Đã bị hủy; contributor có thể rút tiền

Một chi tiết quan trọng: một microsale chỉ finalize khi số tiền raise chạm hard cap chính xác. Các khoản contribute bị giới hạn sao cho totalRaised không bao giờ vượt quá hardCap, và khoản contribute cuối cùng lấp đầy khoảng còn thiếu sẽ set filledAt. Một sale chạm tới thời điểm kết thúc mà chưa được lấp đầy vẫn giữ trạng thái Active nhưng trở thành có thể refund (xem Refund và thoát sale).

Config template​

Bạn không tự đặt phần kinh tế của một sale; bạn chọn từ các template mà platform công bố. Khám phá chúng trước khi hiển thị một form tạo sale:

// Full template objects (recommended for discovery)
const configs = await launchpad.getActiveMicroSaleConfigs();

for (const c of configs) {
console.log({
configId: c.configId,
presaleTokens: c.presaleTokens,
lpTokens: c.lpTokens,
hardCap: c.hardCap, // in the template's raise currency
duration: c.duration, // seconds
active: c.active,
});
}

Các lệnh đọc liên quan:

HàmTrả về
getActiveMicroSaleConfigs()mảng MicroSaleConfig đang active
getActiveMicroSaleConfigIds()mảng các giá trị configId đang active
getMicroSaleConfig(configId)một template
getMicroSaleConfigsCount()tổng số template từng được tạo

Rate được suy ra từ template​

Bạn không tự đặt giá. Launchpad tính toán hai rate từ template và hard cap:

  • Presale rate = presaleTokens * 1e18 / hardCap. Đây là số lượng token unit mà một contributor nhận được trên mỗi đơn vị tiền raise: purchased = amount * rate / 1e18.
  • Listing rate = lpTokens * 1e18 / (hardCap * 0.95). Con số này đặt giá mở cửa trên DEX. Con số 0.95 là 5% phí platform bị trừ ra khỏi số tiền raise trước khi thêm liquidity.

Đồng tiền raise​

Hầu hết template raise bằng đồng coin gốc của chain (BNB). Một số template thay vào đó được gắn với một quote token ERC20. Kiểm tra ràng buộc này trước khi tạo sale hoặc contribute:

const quote = await launchpad.getMicroSaleConfigQuoteToken(configId);
// address(0) => native (BNB) raise
// otherwise => contributors pay with that ERC20

Ràng buộc này áp dụng cho các launch không thuế, fee-receiver ví, và vault. Một đợt raise native dùng contributeMicroSale; một đợt raise ERC20 dùng contributeMicroSaleQuote. Trộn lẫn hai đường sẽ revert.

Quote token được phép​

Các curve microsale và Melt Pool raise bằng đồng coin native của chain hoặc bất kỳ token nào trong allow-list quote token dùng chung của launchpad — đọc nó trực tiếp bằng getAllowedQuoteTokens() và kiểm tra một token bằng isQuoteTokenAllowed(token). Xem Đồng tiền được hỗ trợ để biết danh sách đầy đủ theo từng chain.

Loại token và các đường tạo sale​

Hiện có ba đường tạo sale. Mỗi đường trả về địa chỉ fundManager của sale mới.

HàmTokenThuếĐồng tiền raiseFee receiver
createMicroSaleNoTaxTokenCheeseTokenkhông cónative hoặc ERC20 theo ràng buộc templaten/a
createMicroSaleTaxTokenV2CheeseTaxTokenV2thuế mua/bánnative hoặc ERC20 theo ràng buộc templatemột ví bạn chỉ định
createMicroSaleTaxTokenWithVaultV2CheeseTaxTokenV2thuế mua/bánnative hoặc ERC20 theo ràng buộc templatemột vault được deploy khi launch

Các đường tax-token mint ra một token đánh thuế lệnh mua và bán và định tuyến khoản thu đó tới một fee receiver. Đường thông thường mint một ERC20 bình thường, không thuế và không fee receiver. Chọn đường vault khi bạn muốn khoản thu chảy vào logic payout có thể lập trình được; xem vaults.md.

Xác minh source của token​

Mỗi token được mint bởi một microsale là một trong hai contract: ERC20 thường (CheeseToken) hoặc ERC20 có thu thuế (CheeseTaxTokenV2). Source của chúng được công khai tại cheesepad-ai/cheesepad-contracts. Các ABI có thể tải về và các getter riêng của token được nói tới trong Minted tokens. Điều này cũng áp dụng cho token được mint bởi Melt Pools.

Tạo một microsale​

Tham số dùng chung​

Mọi lệnh create đều nhận các trường sau (bên trong CreateParams):

TrườngKiểuGhi chú
configIduint256template để launch dựa trên; phải đang active
namestringtên token
symbolstringký hiệu token
poolDetailsstringmetadata tự do (JSON, một URL, hoặc bất cứ gì UI của bạn lưu)
maxContributionuint256giới hạn cho tổng contribute của mỗi địa chỉ; 0 nghĩa là không giới hạn
saltbytes32CREATE2 salt mới do CheesePad API trả về
lockDurationuint256thời gian lock LP tính bằng giây; 0 burn LP thay vì lock

Quy tắc của lockDuration: nó phải bằng 0 (LP bị burn lúc finalize) hoặc nằm giữa mức tối thiểu của chain (365 ngày trên cả hai mainnet, 5 phút trên BNB testnet) và trần 10 năm. Bất kỳ giá trị nào khác sẽ revert với Invalid lock duration.

Nếu platform tính phí tạo sale, hãy gửi phí đó dưới dạng msg.value trong lệnh create (xem getting-started.md).

Tạo token salt​

Yêu cầu một salt mới ngay trước mỗi lệnh gọi create. Phản hồi cũng chứa địa chỉ token mà launchpad sẽ deploy. Đừng tái sử dụng một salt cho một launch khác.

type SaltTokenType = "CheeseToken" | "CheeseTaxTokenV2";

async function generateTokenSalt(
tokenType: SaltTokenType,
name: string,
symbol: string,
router: string,
): Promise<{ salt: string; address: string }> {
const { chainId } = await provider.getNetwork();
const query = new URLSearchParams({
tokenType,
launchpadContract: LAUNCHPAD,
chainId: chainId.toString(),
name,
symbol,
router,
});

const response = await fetch(
`https://api.cheesepad.ai/microsale/generate-salt?${query}`,
);
if (!response.ok) {
throw new Error(`Salt generation failed: ${response.status} ${await response.text()}`);
}
return response.json();
}

Truyền vào một trong các router được launchpad hỗ trợ. Với một launch tax-token V2, dùng cùng dexKey mà bạn truyền vào hàm create. API luôn trả về một salt 32-byte và address tương ứng của nó.

Chọn một DEX cho tax token​

Hai lệnh gọi tax-token V2 nhận một dexKey sau các tham số khác của chúng. Dùng một router được hỗ trợ có DEX entry đã được bật:

const [dexKey] = await launchpad.getSupportedRouters();
const dex = await launchpad.getDex(dexKey);
if (!dex.enabled) throw new Error("DEX is not enabled");

Launchpad cung cấp cấu hình venue của DEX đó cho token. Người gọi không cần tìm hay tính toán các pair hash hoặc fee tier.

Token không thuế​

Đường launch đơn giản nhất. Template được chọn quyết định liệu contributor trả bằng đồng tiền native hay một quote token ERC20.

const name = "My Token";
const symbol = "MTK";
const [router] = await launchpad.getSupportedRouters();
if (!router) throw new Error("No supported router");
const { salt, address: predictedToken } = await generateTokenSalt(
"CheeseToken",
name,
symbol,
router,
);

const params = {
configId: 0n,
name,
symbol,
poolDetails: "",
maxContribution: 0n, // unlimited per wallet
salt,
lockDuration: 0n, // burn LP at finalize
};

const creationFee = (await launchpad.getMasterConfig()).microSaleCreationFee;
const tx = await launchpadRW.createMicroSaleNoTaxToken(params, { value: creationFee });
const receipt = await tx.wait();

// The fundManager and token come from the MicroSaleCreated event
const ev = receipt.logs.find((l) => l.eventName === "MicroSaleCreated");
const fundManager = ev.args.fundManager;
const token = ev.args.token;
if (token.toLowerCase() !== predictedToken.toLowerCase()) {
throw new Error("Created token does not match the predicted address");
}

Tax token (fee receiver là một ví)​

Cùng cấu trúc, cộng thêm một taxConfig mô tả thuế và nơi nó chảy tới. Doanh thu được gửi tới một ví thường mà bạn chỉ định.

const name = "Taxed";
const symbol = "TAX";
const { salt, address: predictedToken } = await generateTokenSalt(
"CheeseTaxTokenV2",
name,
symbol,
dexKey,
);

const taxConfig = {
buyTaxBps: 300n, // 3% on buys; each side max 1000 (10%)
sellTaxBps: 500n, // 5% on sells; at least one side must be > 0
taxDuration: 365n * 24n * 60n * 60n, // required; seconds after listing
antiFarmerDuration: 15n * 60n, // taxes every registered venue during this window
allocation: { // must sum to 10000
feeReceiver: 10000, // 100% to the fee receiver in this example
holders: 0,
burn: 0,
liquidity: 0,
},
feeReceiver: "0xYourRevenueWallet",
quoteToken: ethers.ZeroAddress, // launchpad fills WETH for native templates
minHolderShare: 0n, // required > 0 only when holders > 0
v3Factory: ethers.ZeroAddress, // DEX-derived fields are filled by the launchpad
v2PairInitCodeHash: ethers.ZeroHash,
v3PoolInitCodeHash: ethers.ZeroHash,
v3FeeTiers: [],
};

const params = {
configId: 0n, name, symbol, poolDetails: "",
maxContribution: 0n, salt, lockDuration: 0n,
taxConfig,
};

const tx = await launchpadRW.createMicroSaleTaxTokenV2(params, dexKey, {
value: creationFee,
});

Các quy tắc thuế được áp dụng ở thời điểm tạo sale:

  • Mỗi bên buyTaxBps và sellTaxBps tối đa là 1000 (10%), và ít nhất một bên phải lớn hơn không.
  • taxDuration phải lớn hơn không và ít nhất bằng antiFarmerDuration; cả hai đều bị giới hạn ở 150 năm.
  • allocation.feeReceiver + holders + burn + liquidity phải bằng 10000.
  • Fee receiver chỉ nhận được tiền nếu allocation.feeReceiver > 0, nên lệnh create sẽ revert nếu bạn đặt thuế nhưng để slice đó bằng không (sẽ không bao giờ có gì nạp tiền cho receiver).
  • Nếu allocation.holders > 0, bạn phải đặt minHolderShare > 0 (số dư tối thiểu một ví cần có để nhận holder dividend).
  • Các ngưỡng thanh lý thuế (liquidation threshold) là hằng số của token và không phải tham số create.

Các slice trong allocation cho phép một token vừa trả cho một ví, vừa thưởng holder dưới dạng dividend, vừa burn một phần, vừa bơm thêm liquidity, tất cả từ cùng một khoản thuế. Với đường ví thường, đa số dùng feeReceiver: 10000. Các slice holder/burn/liquidity được nói kỹ hơn trong vaults.md.

Tax token với vault​

Fee receiver là một vault được deploy cho bạn bởi một factory bạn chỉ định. Đặt taxConfig.feeReceiver thành địa chỉ không; launchpad sẽ gắn vault đã deploy. Vì các tham số bổ sung và handshake với factory cần giải thích riêng, hướng dẫn đầy đủ nằm ở vaults.md. Signature như sau:

function createMicroSaleTaxTokenWithVaultV2(
CreateParamsV2 calldata params,
address vaultFactory,
bytes calldata vaultData,
address dexKey
) external payable returns (address fundManager);

Tạo một salt riêng cho launch dùng vault và đặt fee receiver thành địa chỉ không:

const { salt, address: predictedToken } = await generateTokenSalt(
"CheeseTaxTokenV2",
params.name,
params.symbol,
dexKey,
);
const vaultParams = {
...params,
salt,
taxConfig: { ...params.taxConfig, feeReceiver: ethers.ZeroAddress },
};

await launchpadRW.createMicroSaleTaxTokenWithVaultV2(
vaultParams,
VAULT_FACTORY,
vaultData,
dexKey,
{ value: creationFee },
);

Đọc lại những gì bạn vừa tạo​

Mỗi lệnh create phát ra MicroSaleCreated(index, fundManager, owner, token, configId, timestamp). Lấy fundManager và token từ đó, hoặc tra cứu lại sale sau này:

const sale = await launchpad.getMicroSaleByFundManager(fundManager);
// or by the token address, or by index
const sameByToken = await launchpad.getMicroSaleByToken(token);

Contribute​

Gọi hàm nào phụ thuộc vào đồng tiền raise của sale. Đọc sale.currency: address(0) nghĩa là raise native, giá trị khác nghĩa là raise ERC20.

Raise native (BNB)​

await launchpadRW.contributeMicroSale(fundManager, {
value: ethers.parseEther("1"), // 1 BNB
});

Raise bằng ERC20 quote​

Approve quote token trước, sau đó contribute một số lượng cụ thể. Không có msg.value.

const quote = new ethers.Contract(sale.currency, ERC20_ABI, signer);
await quote.approve(LAUNCHPAD, amount);
await launchpadRW.contributeMicroSaleQuote(fundManager, amount);

Các quote token có phí khi chuyển (fee-on-transfer) bị từ chối: launchpad kiểm tra rằng số lượng nó nhận được khớp chính xác với amount, nếu không sẽ revert Non-standard quote transfer.

Những gì launchpad kiểm tra ở mỗi lần contribute​

  • Sale đang Active.
  • Thời điểm hiện tại nằm trong khoảng [startTime, endTime).
  • totalRaised + amount <= hardCap (bạn không thể vượt quá cap).
  • Nếu maxContribution > 0, tổng contribute của bạn phải nằm trong giới hạn đó.
  • Khoản mua phải làm tròn ra nhiều hơn không token (amount * rate / 1e18 > 0), nên các khoản quá nhỏ sẽ revert với Contribution too small.

Vì các khoản contribute không thể vượt quá hard cap, số tiền lấp đầy vị trí cuối cùng chính xác bằng hardCap - totalRaised. Hãy báo con số đó cho người dùng để giao dịch của họ không bị revert.

const sale = await launchpad.getMicroSaleByFundManager(fundManager);
const remaining = sale.hardCap - sale.totalRaised;

let maxForUser = remaining;
if (sale.maxContribution > 0n) {
const me = await launchpad.getMicroSaleContribution(fundManager, myAddress);
const headroom = sale.maxContribution - me.contribution;
maxForUser = headroom < remaining ? headroom : remaining;
}

Finalize​

Khi hard cap đã đạt, chủ sở hữu sale finalize nó (một operator của platform cũng có thể làm điều này, đó là cách UI đề nghị finalize thay cho chủ sở hữu). Finalize lấy 5% phí platform, thêm phần còn lại của khoản raise cộng với token LP vào DEX, rồi lock LP (nếu lockDuration > 0) hoặc burn nó.

const sale = await launchpad.getMicroSaleByFundManager(fundManager);
if (sale.totalRaised === sale.hardCap && sale.state === 0n) {
await launchpadRW.finalizeMicroSale(fundManager); // sale owner
}

Sau finalize, sale.state là 1 (Finalized), sale.listedAt là thời điểm listing, và cặp DEX đã sống. Đây là thời điểm một token bắt đầu giao dịch, nên đây là event bạn cần theo dõi nếu bạn track các lần listing (MicroSaleFinalized).

Claim​

Khi một sale đã finalize, mỗi contributor claim số token họ đã mua. Claim là hành động one-shot cho mỗi địa chỉ.

await launchpadRW.claimMicroSale(fundManager); // sends msg.sender their tokens

const me = await launchpad.getMicroSaleContribution(fundManager, myAddress);
console.log("claimed:", me.claimed); // equals `purchased` after a successful claim

Claim sẽ revert nếu sale chưa finalize (MicroSale not finalized), nếu bạn không mua gì (Nothing to claim), hoặc nếu bạn đã claim rồi (Already claimed).

Refund và thoát sale​

Có hai cách để lấy lại tiền, tùy vào tình huống.

Refund toàn phần: sale thất bại hoặc bị hủy​

withdrawMicroSale trả lại 100% một khoản contribute khi một trong hai điều sau xảy ra:

  • sale vẫn Active nhưng endTime đã qua và hard cap chưa bao giờ đạt được (một sale thất bại), hoặc
  • sale bị Cancelled bởi chủ sở hữu của nó.
await launchpadRW.withdrawMicroSale(fundManager); // refunds msg.sender in full

Đây là đường thông thường cho một sale không được lấp đầy. Không có phí.

Thoát sớm khi sale đang mở: emergency withdraw​

emergencyWithdrawMicroSale cho phép một contributor rời khỏi một sale vẫn đang mở và chưa được lấp đầy, với mức phạt 10% (phần phạt chuyển về platform). Hành động này bị chặn trong 15 phút cuối trước endTime.

await launchpadRW.emergencyWithdrawMicroSale(fundManager); // returns 90% to msg.sender

Điều kiện: sale đang Active, hard cap chưa đạt, sale chưa kết thúc, và còn ít nhất 15 phút. Khác với withdraw toàn phần, cách này làm giảm totalRaised của sale, giải phóng chỗ trống đó cho người khác.

Hủy một sale​

Chủ sở hữu có thể hủy một sale đang Active, chuyển nó sang Cancelled và mở withdraw toàn phần cho mọi contributor.

await launchpadRW.cancelMicroSale(fundManager); // sale owner

Chỉnh sửa một sale​

Hai trường vẫn có thể chỉnh sửa sau khi tạo, bởi chủ sở hữu sale (hoặc một operator của platform):

HàmCập nhật
updateMicroSaleDetails(fundManager, poolDetails)metadata tự do; chủ sở hữu chỉ có thể gọi khi sale đang Active, operator có thể gọi bất cứ lúc nào
setMicroSaleMaxContribution(fundManager, maxContribution)giới hạn theo địa chỉ; 0 nghĩa là không giới hạn

Cả hai đều phát ra MicroSaleUpdated(index, fundManager, timestamp).

Đọc trạng thái sale​

Mọi thứ bạn cần cho một dashboard đều là một view call. Tất cả đều mở cho bất kỳ ai.

Tra cứu một sale​

HàmDùng để
getMicroSale(index)theo index tạo sale
getMicroSaleByFundManager(fundManager)theo handle của sale
getMicroSaleByToken(token)theo địa chỉ token (1:1 với sale)
getMicroSaleByVault(vault)theo vault gắn kèm, cho các launch dùng vault
getMicroSalesCount()tổng số sale từng được tạo
isQuoteTokenAllowed(token)liệu một ERC20 có được chấp nhận làm quote token cho launch dùng vault hay không
getAllowedQuoteTokens()mọi ERC20 mà platform chấp nhận làm quote token

Struct MicroSale trả về có đầy đủ trạng thái: state, totalRaised, hardCap, startTime, endTime, filledAt, listedAt, rate, maxContribution, token, currency, vault, và nhiều hơn nữa. Xem events-and-data.md để biết mọi trường.

Tra cứu contributor​

// One user's ledger
const info = await launchpad.getMicroSaleContribution(fundManager, user);
// { contribution, purchased, claimed, excessiveRefunded }

// How many contributors
const n = await launchpad.getMicroSaleContributorCount(fundManager);

// A page of contributors (inclusive indexes; endIndex is clamped to the last one)
const page = await launchpad.getMicroSaleContributionInfos(fundManager, 0, 49);
// [{ user, contribution, purchased, claimed }, ...]

Một helper nhỏ để theo dõi tiến độ​

async function progress(fundManager: string) {
const s = await launchpad.getMicroSaleByFundManager(fundManager);
const pct = (Number(s.totalRaised) / Number(s.hardCap)) * 100;
return {
state: ["Active", "Finalized", "Cancelled"][Number(s.state)],
raised: ethers.formatEther(s.totalRaised),
hardCap: ethers.formatEther(s.hardCap),
percent: pct.toFixed(2),
endsIn: Number(s.endTime) - Math.floor(Date.now() / 1000),
};
}

Địa chỉ token vanity​

Mọi đường tạo sale đều deploy token bằng CREATE2. Dùng helper API generate-salt trước mỗi launch; nó tìm kiếm dựa trên token template on-chain hiện tại và trả về cả một salt duy nhất lẫn địa chỉ token được dự đoán. Địa chỉ trả về kết thúc bằng 6666. Truyền salt trả về nguyên vẹn vào hàm create và dùng address trả về cho việc xem trước trước giao dịch hoặc xác minh sau giao dịch.

Tham chiếu lỗi​

Các revert string bạn có nhiều khả năng gặp nhất, nhóm theo lệnh gọi.

Create

MessageNguyên nhân
Config not found / Config not activeconfigId sai hoặc đã bị vô hiệu hóa
Invalid lock durationlockDuration khác 0 và nằm ngoài khoảng cho phép
Invalid total supplytổng presale + LP token của template không bằng 1e9
Insufficient creation feemsg.value thấp hơn phí tạo sale của platform
Buy tax exceeds max / Sell tax exceeds maxmột bên thuế vượt quá 1000 BPS
Tax must be > 0cả hai bên thuế đều bằng không
Tax duration required / Tax duration too shortthời lượng bằng không hoặc ngắn hơn antiFarmerDuration
Invalid allocationcác slice của tax allocation không cộng lại bằng 10000
Fee receiver requiredđường wallet-receiver với feeReceiver bằng không
Config not bound to this quotetaxConfig.quoteToken không khớp với ràng buộc của template
Dex not enableddexKey không phải một DEX entry đã được bật

Contribute

MessageNguyên nhân
Invalid fund managerđịa chỉ không phải là fund manager của một microsale
Quote sale: use contributeMicroSaleQuotegọi native trên một sale raise bằng ERC20
Native sale: use contributeMicroSalegọi ERC20 trên một sale raise native
MicroSale not activesale đã finalize hoặc bị hủy
Contribution outside of start and end timetrước khi bắt đầu hoặc sau khi kết thúc
Buying amount exceeds hard capsẽ đẩy totalRaised vượt quá cap
Contribute more than allowedvượt quá maxContribution của sale này
Contribution too smalllàm tròn thành không token
Non-standard quote transferquote token có phí khi chuyển

Finalize / claim / withdraw

MessageNguyên nhân
Unauthorizedkhông phải chủ sở hữu sale hoặc một operator của platform
Hard cap not reachedfinalize trước khi cap được lấp đầy chính xác
MicroSale not finalizedclaim trước khi finalize
Nothing to claim / Already claimedclaim mà không có phần được phân bổ, hoặc claim hai lần
Hard cap reachedwithdraw toàn phần trên một sale thực ra đã được lấp đầy
Pool is still in progresswithdraw toàn phần trước khi sale kết thúc
Hard cap already reachedemergency withdraw sau khi cap đã được lấp đầy
Too close to end timeemergency withdraw trong vòng 15 phút cuối
No contributionwithdraw mà không có gì đã contribute