跳到主要内容

用代码发射代币

一次发射在 factory 上以一笔交易创建策略代币、其联合曲线和金库。代币在曲线上以一只已上架股票计价出售;曲线售罄后毕业为 Uniswap v4 池子,金库随即执行创建者在发射时选定的策略。发射之前,创建者须在两个 deployer 上登记各项选择(开盘窗口、免除开盘加价的 钱包、策略类型及其参数),再由 predict 返回发射条款,launchWithMetadata 按该条款完成发射。launchAndBuy 在同一笔交易中完成发射, 并以 ETH 支付创建者的首笔买入。下文的脚本由一个钱包完成上述全部步骤,该钱包即为创建者。

准备事项​

  • 一个持有 ETH 的钱包,用于支付发射费(getDefaults().launchFeeAmount,0.0005 ETH)、至多四笔交易的 gas,以及首笔买入(如有)。 在主网分叉上,发射交易消耗约 1,000 万 gas;每笔登记交易的消耗远低于此。
  • Node.js 及 viem。脚本通过 npx tsx 运行。
  • factory.publicLaunch() 返回 true。
地址
HedgeFunV2Factory0xC78b6A83d75C5612a1A7323702B56038254a6459
CurveDeployer0x501e94d1b06f955C268AE920c42B6289dA5127fd
V2TreasuryDeployer0xD86745C6e81D4095A47979267267c2bf41fBFC46
HedgeFunV2LaunchNativeRouter0xCcFbB947f841170fA7D220f01B6CbbA0487a5cD8
USDG(6 位小数)0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
WETH0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73
Uniswap V3 factory0x1f7d7550B1b028f7571E69A784071F0205FD2EfA
股票,以 TSLA 为例0x322F0929c4625eD5bAd873c95208D54E1c003b2d

十八只已上架股票列于地址页。请使用股票代币地址,并核对 factory.listings(stock):其中 enabled 须为 true。

步骤​

1. 上传图标(可选)​

代币页面仅显示由本站托管的图标。可手动上传,也可按资料和图标所述以脚本上传,并将返回的链接填入 METADATA.logo。logo 为空亦可发射。

2. 登记创建者的选择​

每项登记均须由创建者发送,并以 keccak256(abi.encode(symbol, creator, nonce)) 为键,因此只对这一次发射生效。发射之前,每项登记均可 以新值重新提交。

curveDeployer.setCurveConfig(symbol, nonce, DEFAULT_SALE_BPS(), snipeSeconds) // 7931;窗口 0..180 秒
curveDeployer.setOpeningTaxExemptions(symbol, nonce, wallets) // 至多 MAX_OPENING_TAX_EXEMPTIONS() = 40 个
treasuryDeployer.setStrategyKind(symbol, nonce, kind) // 类型 1、4、5;类型 0 无需调用
treasuryDeployer.setEngineConfig(symbol, nonce, kind, config) // 类型 2、3、6;同时记录类型
  • 开盘窗口。 发射后的 snipeSeconds 秒内,买方适用的费率自 snipeBps(99%)起线性下降,至窗口结束时降为基础税率。未登记时, 窗口长度为 getDefaults().snipeSeconds,主网上为 3 秒。saleBps 必须等于 DEFAULT_SALE_BPS()。
  • 免除名单。 名单内的钱包在窗口期内仅缴纳基础税。上限应从 MAX_OPENING_TAX_EXEMPTIONS()(40)读取;41 个地址的名单会以 BadOpeningTaxExemptions 回滚,名单中含零地址、创建者本人或重复地址时亦然。创建者无需列入名单即自动免除。再次调用将整份替换原名单。
  • 策略类型。 kindManifest(kind) 返回 (engineVersion, configSchema, ...)。schema 为 0 的类型使用 setStrategyKind;引擎类型 (schema 1、3 或 4)使用 setEngineConfig 并传入 {schema, engineVersion, policyKey, words},对引擎类型调用 setStrategyKind 会以 BadKind 回滚。各类型及其编号的含义见核心概念。
  • 循环(5)与预留现金的分批止盈(6) 要求 tp1Bps 与 dipBps 不低于 2 × (listingGates(stock).maxSlippageBps + 池子费率), TSLA 上为 210(75 + 30)。predict 不检查此项,发射时以 TreasuryDeployFailed 回滚。脚本在发送任何交易之前即检查此项。

3. 预测与核对​

(token, treasury, terms) = factory.predict(request)

request.maxFee 应为 launchFeeAmount,request.expectedOpenPriceE18 应为 listings(stock).openPriceE18;取其他值时发射以 Restated 回滚。predict 会拒绝不合规的曲线或引擎参数以及落在执行成本之内的止损,但税率范围、bandBpsPerHour、上述阶梯下限以及 类型 6 中超过 5000 的 reserveBps 仅在发射时才被拒绝。因此脚本在发送每笔交易之前均先行模拟。predict 之后若更改登记,发射将以 Restated 回滚;重新登记报价时的值,或重新执行 predict,即可恢复。

4. 发射​

id = factory.launchWithMetadata{value: launchFeeAmount}(request, terms, metadata)
(id, tokensOut, stockRefund) = launchNativeRouter.launchAndBuy{value: launchFeeAmount + amountIn}(request, terms, metadata, buy, path)

调用 launchWithMetadata 时,msg.value 必须恰好等于发射费,多付或少付均以 BadRequest 回滚。launchAndBuy 经由 HedgeFunV2LaunchNativeRouter 执行,该 router 已获 factory 授权(factory.launchers(0xCcFbB947f841170fA7D220f01B6CbbA0487a5cD8) 为 true)。它支付发射费,将其余 ETH 沿 path(WETH → USDG → 股票)兑换为股票,再替 request.creator 在新曲线上买入,创建者仅缴纳 基础税。buy 为 (amountIn, minStockReceived, minFinalOut, deadline, allowPartialFill);脚本以模拟结果扣除 BUY_SLIPPAGE_BPS 作为 minFinalOut。详见报价与发射及 一次 ETH 付款。

5. 读取结果​

Launched(id, symbol, token, treasury, hook, stock, creator) 事件给出编号与各地址。此后可由 factory.strategies(id) 与 factory.curves(id) 读取上述地址,由 token.getTokenInfo() 读取资料,由 treasuryDeployer.strategyKindOf(salt) 与 engineConfigOf(salt) 读取已冻结的选择,并由曲线的 snipeSeconds() 与 isOpeningTaxExempt(wallet) 核对窗口与免除名单。 其余读取方法见读取状态。

脚本​

将脚本保存为 launch.mts(.mts 扩展名使其在任何包中均可使用顶层 await),修改顶部常量后运行:

npm i viem
RPC_URL=https://rpc.mainnet.chain.robinhood.com CREATOR_KEY=0x... npx tsx launch.mts
// Launch a Hedgefun v2 token on Robinhood Chain mainnet.
// Run: npm i viem && RPC_URL=https://rpc.mainnet.chain.robinhood.com CREATOR_KEY=0x... npx tsx launch.mts
import {
createPublicClient, createWalletClient, encodeAbiParameters, http, keccak256, pad, parseAbi,
parseEther, parseEventLogs, toHex, zeroAddress, type Address, type Hex, type TransactionReceipt,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { robinhood } from 'viem/chains';

// ---------- your choices ----------
const RPC_URL = process.env.RPC_URL ?? 'https://rpc.mainnet.chain.robinhood.com';
const creator = privateKeyToAccount(process.env.CREATOR_KEY as Hex); // the launching wallet is the creator

const STOCK: Address = '0x322F0929c4625eD5bAd873c95208D54E1c003b2d'; // TSLA; any listed stock
const NAME = 'My Strategy';
const SYMBOL = 'MYS';
const NONCE = 0n; // change it to launch the same symbol again from the same wallet
const TAX_BPS = 300; // total trading tax, 100..1500
const CREATOR_BPS = 1000; // creator's share of the collected tax, 0..5000
const RULE = { tp1Bps: 300, tp2Bps: 600, dipBps: 300, stopBps: 0, lotBps: 5000 };
const SNIPE_SECONDS = 60; // opening window with the surcharge, 0..180
const EXEMPT: Address[] = [ // your buyers' wallets; up to MAX_OPENING_TAX_EXEMPTIONS (40); never the creator
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
'0x90F79bf6EB2c4f870365E785982E1f101E93b906',
];
// Strategy kind: 0 Lots, 1 Buy-back, 2 Spot, 3 Rebalance, 4 Percentage buy-back, 5 Cycle, 6 Lots with reserve.
const KIND: number = 6;
// Engine settings, read only for kinds 2, 3 and 6 (bps: 10000 = 100%; cooldown in seconds; USDG in whole units)
const SPOT = { targetBps: 7000, bandBps: 500, cooldown: 600, payoutBps: 5000, maxTradeUsdg: 500n, maxDailyTurnoverUsdg: 5000n };
const REBALANCE = { targetBps: 7000, bandBps: 300, cooldown: 600, payoutBps: 5000, buyBps: 1000, sellBps: 1000, dailyBuyBps: 3000, dailySellBps: 3000 };
const RESERVE = { reserveBps: 2000, cashFloorBps: 0, dipBudgetBps: 0, maxDipBuys: 0 };
const POLICY_KEY: Record<number, Hex> = { // the policy registered for each engine kind on mainnet
2: '0x0bbb627010933ceb50697c684afa18c7a8e16bad2db2fa0f0ab599f8c594876b', // V2RebalancePolicy, schema 1
3: '0xc03e442b589ccf8ee11bdac143e02af08155bfcf764d7a59b55ec1ae1eac6c44', // V2TradablePercentRebalancePolicy, schema 3
6: '0xbd4bcc5bf76c731539ed5855053e90ea8822b8886afd75bd751d0f72f792a468', // V2LotReservePolicy, schema 4
};
const METADATA = {
logo: '', // https://hedgefun.trade/media/icons/<sha256>.png from the icon upload, or empty
description: 'A strategy token on TSLA.',
socials: { twitter: '', telegram: '', discord: '', website: '', farcaster: '' },
extraURI: '',
};
const FIRST_BUY_ETH: string = '0'; // ETH the creator spends on the new curve in the launch transaction; '0' = no buy
const BUY_SLIPPAGE_BPS = 300;

// ---------- mainnet addresses ----------
const FACTORY: Address = '0xC78b6A83d75C5612a1A7323702B56038254a6459';
const CURVE_DEPLOYER: Address = '0x501e94d1b06f955C268AE920c42B6289dA5127fd';
const TREASURY_DEPLOYER: Address = '0xD86745C6e81D4095A47979267267c2bf41fBFC46';
const LAUNCH_ROUTER: Address = '0xCcFbB947f841170fA7D220f01B6CbbA0487a5cD8';
const WETH: Address = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';
const USDG: Address = '0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168';
const V3_FACTORY: Address = '0x1f7d7550B1b028f7571E69A784071F0205FD2EfA';

const structs = [
'struct Request { string name; string symbol; address stock; address creator; uint16 taxBps; uint16 creatorBps; uint32 tp1Bps; uint32 tp2Bps; uint16 dipBps; uint16 stopBps; uint16 lotBps; uint16 bandBpsPerHour; uint96 nonce; uint256 maxFee; uint256 expectedOpenPriceE18; }',
'struct Socials { string twitter; string telegram; string discord; string website; string farcaster; }',
'struct Info { string logo; string description; Socials socials; string extraURI; }',
'struct Defaults { uint256 supply; uint24 lpFee; int24 tickSpacing; uint16 minTaxBps; uint16 maxTaxBps; uint16 protocolBps; uint16 maxCreatorBps; uint16 spikeBps; uint32 spikeSeconds; uint16 sweepTipBps; uint16 snipeBps; uint8 snipeSeconds; uint16 bountyBps; uint16 maxSlippageBps; uint16 maxDeviationBps; uint16 maxBuybackImpactBps; uint32 buybackCooldown; uint256 minLotUsdg; uint256 buybackChunkUsdg; uint256 sellChunkUsdg; uint8 launchFeeCurrency; uint256 launchFeeAmount; }',
'struct EngineConfig { uint32 schema; uint32 engineVersion; bytes32 policyKey; bytes32[3] words; }',
'struct Buy { uint256 amountIn; uint256 minStockReceived; uint256 minFinalOut; uint256 deadline; bool allowPartialFill; }',
'struct Hop { address pool; address tokenOut; }',
];
const abi = parseAbi([
...structs,
'function getDefaults() view returns (Defaults)',
'function publicLaunch() view returns (bool)',
'function listings(address) view returns (address oracle, address v3Pool, uint256 openPriceE18, bool enabled)',
'function listingGates(address) view returns (uint16 maxDeviationBps, uint16 maxSlippageBps, uint64 sellChunkUsdg)',
'function predict(Request) view returns (address token, address treasury, bytes32 terms)',
'function launchWithMetadata(Request, bytes32 terms, Info) payable returns (uint256)',
'function curves(uint256) view returns (address)',
'function MAX_OPENING_TAX_EXEMPTIONS() view returns (uint8)',
'function DEFAULT_SALE_BPS() view returns (uint16)',
'function setCurveConfig(string symbol, uint96 nonce, uint16 saleBps, uint8 snipeSeconds)',
'function setOpeningTaxExemptions(string symbol, uint96 nonce, address[] recipients)',
'function kindManifest(uint8) view returns (uint32 engineVersion, uint32 configSchema, bytes32 creationCodeHash, uint256 capabilities)',
'function setStrategyKind(string symbol, uint96 nonce, uint8 kind)',
'function setEngineConfig(string symbol, uint96 nonce, uint8 kind, EngineConfig config)',
'function strategyKindOf(bytes32) view returns (uint8)',
'function launchAndBuy(Request, bytes32 terms, Info, Buy, Hop[]) payable returns (uint256 id, uint256 tokensOut, uint256 stockRefund)',
'function getPool(address, address, uint24) view returns (address)',
'function liquidity() view returns (uint128)',
'function fee() view returns (uint24)',
'function getTokenInfo() view returns (address deployer, string logo, string description, Socials socials)',
'function balanceOf(address) view returns (uint256)',
// errors, so that a revert is reported by name
'error NotOpen()', 'error NotListed()', 'error BadRequest()', 'error Restated()', 'error Unseedable()',
'error BadCurveConfig()', 'error BadOpeningTaxExemptions()', 'error BadKind()', 'error BadPolicy()',
'error BadEngineConfig()', 'error BadConfig()', 'error TreasuryDeployFailed()',
'error StopInsideExecutionFriction(uint256 stopBps, uint256 minimumExclusiveBps)', 'error BadPayment()',
]);
const events = parseAbi([
'event Launched(uint256 indexed id, string symbol, address token, address treasury, address hook, address stock, address creator)',
]);

const chain = { ...robinhood, rpcUrls: { default: { http: [RPC_URL] } } };
const client = createPublicClient({ chain, transport: http(RPC_URL) });
const wallet = createWalletClient({ chain, transport: http(RPC_URL), account: creator });

async function send(address: Address, functionName: string, args: unknown[], value = 0n) {
const { request } = await client.simulateContract({ address, abi, functionName, args, value, account: creator } as never);
const hash = await wallet.writeContract(request as never);
const receipt = await client.waitForTransactionReceipt({ hash });
if (receipt.status !== 'success') throw new Error(`${functionName} reverted: ${hash}`);
console.log(`${functionName}: ${hash}`);
return receipt;
}
const read = (address: Address, functionName: string, args: unknown[] = []) =>
client.readContract({ address, abi, functionName, args } as never) as Promise<any>;

// ---------- 1. checks ----------
const defaults = await read(FACTORY, 'getDefaults');
if (!(await read(FACTORY, 'publicLaunch'))) throw new Error('Public launching is not open yet');
if (defaults.launchFeeCurrency !== 1) throw new Error('This script pays the launch fee in ETH');
if (TAX_BPS < defaults.minTaxBps || TAX_BPS > defaults.maxTaxBps || CREATOR_BPS > defaults.maxCreatorBps) {
throw new Error(`taxBps ${defaults.minTaxBps}..${defaults.maxTaxBps}, creatorBps at most ${defaults.maxCreatorBps}`);
}
const [, stockPool, openPriceE18, listed] = await read(FACTORY, 'listings', [STOCK]);
if (!listed) throw new Error('Stock is not listed');
const cap = Number(await read(CURVE_DEPLOYER, 'MAX_OPENING_TAX_EXEMPTIONS'));
if (EXEMPT.length > cap) throw new Error(`At most ${cap} exemptions`);
const [engineVersion, schema] = await read(TREASURY_DEPLOYER, 'kindManifest', [KIND]);
if (KIND === 5 || KIND === 6) {
// Cycle and Lots with reserve: the treasury refuses rungs under 2 x (slippage + pool fee) only at launch
const [, maxSlippageBps] = await read(FACTORY, 'listingGates', [STOCK]);
const floor = 2 * (maxSlippageBps + Number(await read(stockPool, 'fee')) / 100);
if (RULE.tp1Bps < floor || RULE.dipBps < floor) throw new Error(`tp1Bps and dipBps must be at least ${floor}`);
}

// ---------- 2. register the creator's choices ----------
await send(CURVE_DEPLOYER, 'setCurveConfig', [SYMBOL, NONCE, await read(CURVE_DEPLOYER, 'DEFAULT_SALE_BPS'), SNIPE_SECONDS]);
if (EXEMPT.length > 0) await send(CURVE_DEPLOYER, 'setOpeningTaxExemptions', [SYMBOL, NONCE, EXEMPT]);
if (schema === 0) {
if (KIND !== 0) await send(TREASURY_DEPLOYER, 'setStrategyKind', [SYMBOL, NONCE, KIND]);
} else {
// an engine kind: setEngineConfig records the kind and its three config words together
const word = (v: bigint) => pad(toHex(v), { size: 32 });
const head = (c: { targetBps: number; bandBps: number; cooldown: number; payoutBps: number }) =>
word(BigInt(c.targetBps) | (BigInt(c.bandBps) << 16n) | (BigInt(c.cooldown) << 32n) | (BigInt(c.payoutBps) << 64n));
const usdg = (v: bigint) => word(v * 10n ** 6n); // USDG has 6 decimals
const words =
schema === 1 ? [head(SPOT), usdg(SPOT.maxTradeUsdg), usdg(SPOT.maxDailyTurnoverUsdg)]
: schema === 3 ? [head(REBALANCE), word(BigInt(REBALANCE.buyBps) | (BigInt(REBALANCE.sellBps) << 16n)),
word(BigInt(REBALANCE.dailyBuyBps) | (BigInt(REBALANCE.dailySellBps) << 16n))]
: schema === 4 ? [word(BigInt(RESERVE.reserveBps)),
word(BigInt(RESERVE.cashFloorBps) | (BigInt(RESERVE.dipBudgetBps) << 16n) | (BigInt(RESERVE.maxDipBuys) << 32n)), word(0n)]
: undefined;
if (!words) throw new Error(`Unknown config schema ${schema}`);
await send(TREASURY_DEPLOYER, 'setEngineConfig', [SYMBOL, NONCE, KIND, { schema, engineVersion, policyKey: POLICY_KEY[KIND], words }]);
}

// ---------- 3. predict ----------
const request = {
name: NAME, symbol: SYMBOL, stock: STOCK, creator: creator.address, taxBps: TAX_BPS, creatorBps: CREATOR_BPS,
...RULE, bandBpsPerHour: 0, nonce: NONCE, maxFee: defaults.launchFeeAmount, expectedOpenPriceE18: openPriceE18,
};
const [token, treasury, terms] = await read(FACTORY, 'predict', [request]);
console.log('predicted token', token, 'treasury', treasury);

// ---------- 4. launch ----------
let receipt: TransactionReceipt;
if (FIRST_BUY_ETH === '0') {
receipt = await send(FACTORY, 'launchWithMetadata', [request, terms, METADATA], defaults.launchFeeAmount);
} else {
// ETH reaches the stock as WETH -> USDG -> stock; use the WETH/USDG pool with the most liquidity
let wethPool: Address = zeroAddress, best = -1n;
for (const fee of [100, 500, 3000, 10000]) {
const pool: Address = await read(V3_FACTORY, 'getPool', [WETH, USDG, fee]);
if (pool === zeroAddress) continue;
const liquidity: bigint = await read(pool, 'liquidity');
if (liquidity > best) [wethPool, best] = [pool, liquidity];
}
const path = [{ pool: wethPool, tokenOut: USDG }, { pool: stockPool, tokenOut: STOCK }];
const amountIn = parseEther(FIRST_BUY_ETH);
const deadline = (await client.getBlock()).timestamp + 600n;
const buy = { amountIn, minStockReceived: 1n, minFinalOut: 1n, deadline, allowPartialFill: false };
const value = defaults.launchFeeAmount + amountIn;
const { result } = await client.simulateContract({
address: LAUNCH_ROUTER, abi, functionName: 'launchAndBuy', args: [request, terms, METADATA, buy, path], value, account: creator,
});
buy.minFinalOut = (result[1] * BigInt(10_000 - BUY_SLIPPAGE_BPS)) / 10_000n;
receipt = await send(LAUNCH_ROUTER, 'launchAndBuy', [request, terms, METADATA, buy, path], value);
}

// ---------- 5. read the result ----------
const [launched] = parseEventLogs({ abi: events, eventName: 'Launched', logs: receipt.logs });
const id = launched.args.id;
const salt = keccak256(encodeAbiParameters([{ type: 'string' }, { type: 'address' }, { type: 'uint96' }], [SYMBOL, creator.address, NONCE]));
console.log({
id,
token: launched.args.token,
treasury: launched.args.treasury,
curve: await read(FACTORY, 'curves', [id]),
kind: await read(TREASURY_DEPLOYER, 'strategyKindOf', [salt]),
metadata: await read(launched.args.token, 'getTokenInfo'),
creatorTokens: await read(launched.args.token, 'balanceOf', [creator.address]),
});

脚本每次运行都会重新发送各项登记,这在发射之前没有影响。发射之后,同一钱包不能以相同的 SYMBOL 与 NONCE 再次发射 (TokenDeployFailed),须更换 NONCE。

在分叉上试运行​

可使用 anvil 在主网的本地分叉上原样运行脚本:

anvil --fork-url https://rpc.mainnet.chain.robinhood.com --port 8545
# anvil's default accounts carry an EIP-7702 delegation on mainnet; clear it on the fork for account 0
cast rpc --rpc-url http://127.0.0.1:8545 anvil_setCode 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 0x
# only while publicLaunch() is false: open it on the fork as the owner Safe
SAFE=0x2910117dd2cB431173Ae9Fb6eAF30726321d1693
cast rpc --rpc-url http://127.0.0.1:8545 anvil_impersonateAccount $SAFE
cast rpc --rpc-url http://127.0.0.1:8545 anvil_setBalance $SAFE 0xDE0B6B3A7640000
cast send --rpc-url http://127.0.0.1:8545 --unlocked --from $SAFE \
0xC78b6A83d75C5612a1A7323702B56038254a6459 'setPublicLaunch(bool)' true
RPC_URL=http://127.0.0.1:8545 CREATOR_KEY=<anvil account 0 key> npx tsx launch.mts

anvil 的默认账户在主网上带有 EIP-7702 委托代码,因此须先在分叉上清除;setPublicLaunch 一步仅在 publicLaunch() 仍为 false 时需要。

参数速查​

字段含义允许范围默认值或示例
name、symbol代币名称与代码symbol + 创建者 + nonce 此前未发射过
stock曲线与池子所对应的已上架股票listings(stock).enabledTSLA
creator获得所收税款的 creatorBps;负责发送各项登记EOA 或 Safe发射钱包
taxBps交易总税率minTaxBps..maxTaxBps:100..1500100(发布推荐值)
creatorBps创建者在所收税款中的份额0..maxCreatorBps:0..50000(发布推荐值)
tp1Bps、tp2Bps、dipBps、stopBps、lotBps金库规则;各类型下的含义见核心概念tp2Bps 为 0 或大于 tp1Bps(否则 BadConfig);类型 5、6:tp1Bps、dipBps 不低于阶梯下限;类型 1、4、5:非零的 stopBps 须高于滑点 + 池子费率 + 奖励(TSLA 上为 115)由创建者决定;脚本使用 300、600、300、0、5000
bandBpsPerHour陈旧价格带0..bandCeiling(stock)0
nonce区分同一创建者对同一代码的多次发射uint960
maxFee发射方愿意支付的最高发射费launchFeeAmount0.0005 ETH
expectedOpenPriceE18上架的开盘价listings(stock).openPriceE18从链上读取
saleBps在曲线上出售的供应量比例仅限 DEFAULT_SALE_BPS()7931
snipeSeconds收取开盘加价的窗口0..180未登记时为 3
免除名单不缴纳开盘加价的钱包至多 40 个;不得为零地址、创建者本人或重复地址买方钱包
类型金库的策略0..kindCount()-1(0..6)0
Spot(2)targetBps、bandBps、cooldown、payoutBps;maxTradeUsdg、maxDailyTurnoverUsdg目标 2000..9000;区间不低于 2 × (滑点 + 池子费率 + 奖励),小于目标,且目标 + 区间小于 10000;冷却不少于 60 秒;payout 0..10000;单笔上限介于 minLotUsdg(5 USDG)与 sellChunkUsdg(2,000 USDG)之间;每日上限介于单笔上限与其 24 倍之间脚本:7000、500、600、5000;500、5,000 USDG
Rebalance(3)targetBps、bandBps、cooldown、payoutBps;buyBps、sellBps;每日买入与卖出比例目标 2000..9000;区间不低于池子费率 + 奖励,小于目标,且目标 + 区间小于 10000;冷却不少于 60 秒;买入与卖出 1..2500;每日 1..10000脚本:7000、300、600、5000;1000、1000;3000、3000
预留现金的分批止盈(6)reserveBps、cashFloorBps、dipBudgetBps、maxDipBuys预留 0..5000;现金下限与预算 0..10000;抄底次数 0..65535;为 0 时该项限制不生效脚本:2000、0、0、0

回滚原因​

错误原因处理
NotOpen公开发射尚未开放,且发送方不是已授权的 launcher等待 publicLaunch() 开放
BadCurveConfigsaleBps 不等于 7931,或 snipeSeconds 超过 180使用 DEFAULT_SALE_BPS(),窗口取 0..180
BadOpeningTaxExemptions名单超过 40 个,或含零地址、创建者本人、重复地址精简名单,不列入创建者
BadKind对引擎类型调用 setStrategyKind,或类型不存在类型 2、3、6 使用 setEngineConfig
BadPolicypolicy key 与类型不符使用该类型对应的 key
BadEngineConfig引擎参数超出速查表中的范围修正参数
StopInsideExecutionFriction(stop, min)非零的 stopBps 不高于滑点 + 池子费率 + 奖励设为 0,或高于 min
BadConfigtp2Bps 既不为 0,也不大于 tp1Bps修正规则
BadRequest发射时 taxBps 或 creatorBps 越界、bandBpsPerHour 超过上限,或 msg.value 不等于发射费读取 getDefaults();恰好支付 launchFeeAmount
Restatedpredict 之后更改了登记,或 maxFee、expectedOpenPriceE18 不是链上当前值重新登记报价时的值,或重新执行 predict
TreasuryDeployFailed类型 5 或 6 的 tp1Bps 或 dipBps 低于阶梯下限,或类型 6 的 reserveBps 超过 5000提高阶梯;预留不超过 5000
TokenDeployFailed该创建者已用相同的 symbol 与 nonce 发射过更换 NONCE
无原因对未上架的股票执行 predict选择已上架的股票

相关​