@baseline-markets/cli 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -0
- package/dist/index.js +464 -0
- package/package.json +45 -0
- package/skills/aeon-baseline/SKILL.md +154 -0
- package/skills/bankr-baseline/SKILL.md +260 -0
- package/skills/base-mcp-baseline/SKILL.md +33 -0
- package/skills/base-mcp-baseline/plugins/baseline.md +240 -0
- package/skills/launch/SKILL.md +106 -0
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Baseline CLI
|
|
2
|
+
|
|
3
|
+
CLI for building and executing Baseline token launch calls.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Run without installing:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx @baseline-markets/cli launch --help
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install globally:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install -g @baseline-markets/cli
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
For local development:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
bun run --cwd packages/cli dev --help
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Launch Calls
|
|
26
|
+
|
|
27
|
+
Build launch calls without sending transactions:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
baseline launch \
|
|
31
|
+
--chain-id 84532 \
|
|
32
|
+
--name "Smoke Test" \
|
|
33
|
+
--symbol SMOKE \
|
|
34
|
+
--reserve 0xB85885897D297000A74eA2e4711C3Ca729461ABC \
|
|
35
|
+
--total-supply 1000000 \
|
|
36
|
+
--format json
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Execute A Launch
|
|
40
|
+
|
|
41
|
+
Execute with a private key:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
baseline launch \
|
|
45
|
+
--chain-id 84532 \
|
|
46
|
+
--name "Smoke Test" \
|
|
47
|
+
--symbol SMOKE \
|
|
48
|
+
--reserve 0xB85885897D297000A74eA2e4711C3Ca729461ABC \
|
|
49
|
+
--total-supply 1000000 \
|
|
50
|
+
--execute \
|
|
51
|
+
--private-key 0x...
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or use `.env`:
|
|
55
|
+
|
|
56
|
+
```env
|
|
57
|
+
BASELINE_PRIVATE_KEY=0x...
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The deployer account is derived from the private key when `--execute` is used
|
|
61
|
+
and `--account` is omitted.
|
|
62
|
+
|
|
63
|
+
## Launch Modes
|
|
64
|
+
|
|
65
|
+
`zrp` is the default zero-reserve launch:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
--mode zrp
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The pool BToken amount is derived from `--total-supply`.
|
|
72
|
+
|
|
73
|
+
`standard` launches with initial reserve liquidity:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
--mode standard \
|
|
77
|
+
--initial-pool-btokens 950000 \
|
|
78
|
+
--initial-pool-reserves 10
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Environment
|
|
82
|
+
|
|
83
|
+
- `BASELINE_PRIVATE_KEY`: signer used by `--execute`
|
|
84
|
+
- `RPC_URL`: Base Sepolia fork source for integration tests
|
|
85
|
+
|
|
86
|
+
## Tests
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
bun run --cwd packages/cli test
|
|
90
|
+
bun run --cwd packages/cli typecheck
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Fork integration tests:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
RPC_URL=https://sepolia.base.org bun run --cwd packages/cli test:integration
|
|
97
|
+
```
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Cli } from "incur";
|
|
5
|
+
|
|
6
|
+
// src/commands/info.ts
|
|
7
|
+
import { BaselineSDK } from "@baseline-markets/sdk";
|
|
8
|
+
|
|
9
|
+
// ../chains/index.ts
|
|
10
|
+
import { defineChain } from "viem";
|
|
11
|
+
import {
|
|
12
|
+
arbitrum as arbitrumMainnet,
|
|
13
|
+
base as baseMainnet,
|
|
14
|
+
baseSepolia as baseTestnet,
|
|
15
|
+
mainnet as ethereumMainnet
|
|
16
|
+
} from "viem/chains";
|
|
17
|
+
var chains = {
|
|
18
|
+
mainnet: defineChain({
|
|
19
|
+
...ethereumMainnet,
|
|
20
|
+
name: "ethereum",
|
|
21
|
+
rpcUrls: {
|
|
22
|
+
default: {
|
|
23
|
+
http: [
|
|
24
|
+
"https://wispy-hidden-knowledge.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471",
|
|
25
|
+
"https://alien-intensive-butterfly.quiknode.pro/05e4b943102cba88219029212abcd33ee4d95b16"
|
|
26
|
+
],
|
|
27
|
+
webSocket: [
|
|
28
|
+
"wss://wispy-hidden-knowledge.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}),
|
|
33
|
+
arbitrum: defineChain({
|
|
34
|
+
...arbitrumMainnet,
|
|
35
|
+
name: "arbitrum",
|
|
36
|
+
rpcUrls: {
|
|
37
|
+
default: {
|
|
38
|
+
http: [
|
|
39
|
+
"https://wispy-hidden-knowledge.arbitrum-mainnet.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471",
|
|
40
|
+
"https://alien-intensive-butterfly.arbitrum-mainnet.quiknode.pro/05e4b943102cba88219029212abcd33ee4d95b16"
|
|
41
|
+
],
|
|
42
|
+
webSocket: [
|
|
43
|
+
"wss://wispy-hidden-knowledge.arbitrum-mainnet.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}),
|
|
48
|
+
base: defineChain({
|
|
49
|
+
...baseMainnet,
|
|
50
|
+
name: "base",
|
|
51
|
+
rpcUrls: {
|
|
52
|
+
default: {
|
|
53
|
+
http: [
|
|
54
|
+
"https://wispy-hidden-knowledge.base-mainnet.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471/",
|
|
55
|
+
"https://lb.routeme.sh/rpc/8453/251d0417-55cf-4ce5-bab5-3e105247084a",
|
|
56
|
+
"https://alien-intensive-butterfly.base-mainnet.quiknode.pro/05e4b943102cba88219029212abcd33ee4d95b16"
|
|
57
|
+
],
|
|
58
|
+
webSocket: [
|
|
59
|
+
"wss://wispy-hidden-knowledge.base-mainnet.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}),
|
|
64
|
+
baseSepolia: defineChain({
|
|
65
|
+
...baseTestnet,
|
|
66
|
+
name: "base-sepolia",
|
|
67
|
+
rpcUrls: {
|
|
68
|
+
default: {
|
|
69
|
+
http: [
|
|
70
|
+
"https://wispy-hidden-knowledge.base-sepolia.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471"
|
|
71
|
+
],
|
|
72
|
+
webSocket: [
|
|
73
|
+
"wss://wispy-hidden-knowledge.base-sepolia.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471"
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
};
|
|
79
|
+
var chains_default = chains;
|
|
80
|
+
|
|
81
|
+
// src/commands/info.ts
|
|
82
|
+
import { z as z2 } from "incur";
|
|
83
|
+
import { createPublicClient, formatUnits, http } from "viem";
|
|
84
|
+
|
|
85
|
+
// src/commands/common.ts
|
|
86
|
+
import { z } from "incur";
|
|
87
|
+
import { isAddress } from "viem";
|
|
88
|
+
var chainById = {
|
|
89
|
+
[chains_default.mainnet.id]: chains_default.mainnet,
|
|
90
|
+
[chains_default.base.id]: chains_default.base,
|
|
91
|
+
[chains_default.baseSepolia.id]: chains_default.baseSepolia
|
|
92
|
+
};
|
|
93
|
+
function getChain(chainId) {
|
|
94
|
+
const chain = chainById[chainId];
|
|
95
|
+
if (!chain) {
|
|
96
|
+
throw new Error(`Unsupported chain ID: ${chainId}`);
|
|
97
|
+
}
|
|
98
|
+
return chain;
|
|
99
|
+
}
|
|
100
|
+
var address = (label) => z.string().refine((value) => isAddress(value), {
|
|
101
|
+
message: `Invalid ${label} address`
|
|
102
|
+
});
|
|
103
|
+
function buildTokenLinks(chain, token) {
|
|
104
|
+
const appBaseUrl = chain.id === chains_default.baseSepolia.id ? "https://dev.app.baseline.markets" : "https://app.baseline.markets";
|
|
105
|
+
const explorerBaseUrl = chain.blockExplorers?.default.url;
|
|
106
|
+
return {
|
|
107
|
+
appUrl: `${appBaseUrl}/tokens/${chain.id}/${token}`,
|
|
108
|
+
explorerUrl: explorerBaseUrl ? `${explorerBaseUrl}/address/${token}` : undefined
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/commands/info.ts
|
|
113
|
+
var optionSchema = z2.object({
|
|
114
|
+
chainId: z2.coerce.number().default(chains_default.baseSepolia.id).describe("Chain ID for the token."),
|
|
115
|
+
rpcUrl: z2.string().optional().describe("RPC URL for read calls."),
|
|
116
|
+
token: address("token").optional().describe("Token address to inspect.")
|
|
117
|
+
});
|
|
118
|
+
var argsSchema = z2.object({
|
|
119
|
+
token: address("token").optional().describe("Token address to inspect.")
|
|
120
|
+
});
|
|
121
|
+
var infoCommand = {
|
|
122
|
+
description: "Inspect a deployed Baseline token.",
|
|
123
|
+
args: argsSchema,
|
|
124
|
+
options: optionSchema,
|
|
125
|
+
async run(c) {
|
|
126
|
+
const chain = getChain(c.options.chainId);
|
|
127
|
+
const token = c.options.token ?? c.args.token;
|
|
128
|
+
if (!token) {
|
|
129
|
+
throw new Error("Token address is required. Pass it as an argument or --token.");
|
|
130
|
+
}
|
|
131
|
+
const sdk = new BaselineSDK(createPublicClient({
|
|
132
|
+
chain,
|
|
133
|
+
transport: http(c.options.rpcUrl)
|
|
134
|
+
}));
|
|
135
|
+
const info = await sdk.getBTokenInfo(token);
|
|
136
|
+
return serializeBTokenInfo(info, buildTokenLinks(chain, info.bToken));
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
function serializeBTokenInfo(info, links) {
|
|
140
|
+
const decimals = info.decimals ?? 18;
|
|
141
|
+
const reserveDecimals = info.reserveDecimals ?? 18;
|
|
142
|
+
return {
|
|
143
|
+
chainId: info.chainId,
|
|
144
|
+
relay: info.relay,
|
|
145
|
+
bToken: info.bToken,
|
|
146
|
+
status: info.status,
|
|
147
|
+
bytecode: info.bytecode,
|
|
148
|
+
name: info.name,
|
|
149
|
+
symbol: info.symbol,
|
|
150
|
+
decimals: info.decimals,
|
|
151
|
+
totalSupply: stringify(info.totalSupply),
|
|
152
|
+
totalSupplyFormatted: formatTokenAmount(info.totalSupply, decimals),
|
|
153
|
+
reserve: info.reserve,
|
|
154
|
+
reserveDecimals: info.reserveDecimals,
|
|
155
|
+
creator: info.creator,
|
|
156
|
+
poolFeeRecipient: info.poolFeeRecipient,
|
|
157
|
+
creatorFeePct: stringify(info.creatorFeePct),
|
|
158
|
+
creatorFeePctFormatted: formatPct(info.creatorFeePct),
|
|
159
|
+
swapFee: stringify(info.swapFee),
|
|
160
|
+
swapFeeFormatted: formatPct(info.swapFee),
|
|
161
|
+
totalBTokens: stringify(info.totalBTokens),
|
|
162
|
+
totalBTokensFormatted: formatTokenAmount(info.totalBTokens, decimals),
|
|
163
|
+
totalReserves: stringify(info.totalReserves),
|
|
164
|
+
totalReservesFormatted: formatTokenAmount(info.totalReserves, reserveDecimals),
|
|
165
|
+
maker: info.maker ? {
|
|
166
|
+
initialized: info.maker.initialized,
|
|
167
|
+
blvPrice: info.maker.blvPrice.toString(),
|
|
168
|
+
swapFee: info.maker.swapFee.toString(),
|
|
169
|
+
maxCirc: info.maker.maxCirc.toString(),
|
|
170
|
+
maxReserves: info.maker.maxReserves.toString(),
|
|
171
|
+
convexityExp: info.maker.convexityExp.toString(),
|
|
172
|
+
lastInvariant: info.maker.lastInvariant.toString()
|
|
173
|
+
} : undefined,
|
|
174
|
+
links
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function stringify(value) {
|
|
178
|
+
return value === undefined ? undefined : value.toString();
|
|
179
|
+
}
|
|
180
|
+
function formatTokenAmount(value, decimals) {
|
|
181
|
+
return value === undefined ? undefined : trimDecimal(formatUnits(value, decimals));
|
|
182
|
+
}
|
|
183
|
+
function formatPct(value) {
|
|
184
|
+
if (value === undefined)
|
|
185
|
+
return;
|
|
186
|
+
return `${trimDecimal(formatUnits(value * 100n, 18))}%`;
|
|
187
|
+
}
|
|
188
|
+
function trimDecimal(value) {
|
|
189
|
+
return value.includes(".") ? value.replace(/\.?0+$/, "") : value;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// src/commands/launch.ts
|
|
193
|
+
import { BaselineSDK as BaselineSDK2, serializeCalls } from "@baseline-markets/sdk";
|
|
194
|
+
import { z as z3 } from "incur";
|
|
195
|
+
import { writeFile } from "node:fs/promises";
|
|
196
|
+
import {
|
|
197
|
+
createPublicClient as createPublicClient3,
|
|
198
|
+
http as http3,
|
|
199
|
+
parseUnits
|
|
200
|
+
} from "viem";
|
|
201
|
+
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
202
|
+
|
|
203
|
+
// src/commands/tx.ts
|
|
204
|
+
import {
|
|
205
|
+
createPublicClient as createPublicClient2,
|
|
206
|
+
createWalletClient,
|
|
207
|
+
http as http2
|
|
208
|
+
} from "viem";
|
|
209
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
210
|
+
function parsePrivateKey(value) {
|
|
211
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {
|
|
212
|
+
throw new Error("BASELINE_PRIVATE_KEY must be a 32-byte hex private key.");
|
|
213
|
+
}
|
|
214
|
+
return value;
|
|
215
|
+
}
|
|
216
|
+
async function estimateCallGas(estimate, retryDelayMs = 1000) {
|
|
217
|
+
let lastError;
|
|
218
|
+
for (let attempt = 0;attempt < 5; attempt++) {
|
|
219
|
+
try {
|
|
220
|
+
return await estimate();
|
|
221
|
+
} catch (error) {
|
|
222
|
+
lastError = error;
|
|
223
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
throw lastError;
|
|
227
|
+
}
|
|
228
|
+
async function executeCalls(input) {
|
|
229
|
+
const account = privateKeyToAccount(input.privateKey);
|
|
230
|
+
if (input.expectedAccount && account.address.toLowerCase() !== input.expectedAccount.toLowerCase()) {
|
|
231
|
+
throw new Error(`Private key address ${account.address} does not match expected account ${input.expectedAccount}.`);
|
|
232
|
+
}
|
|
233
|
+
const transport = http2(input.rpcUrl);
|
|
234
|
+
const publicClient = createPublicClient2({ chain: input.chain, transport });
|
|
235
|
+
const walletClient = createWalletClient({
|
|
236
|
+
account,
|
|
237
|
+
chain: input.chain,
|
|
238
|
+
transport
|
|
239
|
+
});
|
|
240
|
+
const transactions = [];
|
|
241
|
+
for (const [index, call] of input.calls.entries()) {
|
|
242
|
+
const gas = await estimateCallGas(() => publicClient.estimateGas({
|
|
243
|
+
account: account.address,
|
|
244
|
+
to: call.to,
|
|
245
|
+
data: call.data,
|
|
246
|
+
value: call.value ?? 0n
|
|
247
|
+
})) + 50000n;
|
|
248
|
+
const hash = await walletClient.sendTransaction({
|
|
249
|
+
account,
|
|
250
|
+
chain: input.chain,
|
|
251
|
+
to: call.to,
|
|
252
|
+
data: call.data,
|
|
253
|
+
value: call.value ?? 0n,
|
|
254
|
+
gas
|
|
255
|
+
});
|
|
256
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
257
|
+
if (receipt.status !== "success") {
|
|
258
|
+
throw new Error(`Transaction ${index} reverted: ${hash}`);
|
|
259
|
+
}
|
|
260
|
+
transactions.push({
|
|
261
|
+
index,
|
|
262
|
+
hash,
|
|
263
|
+
status: receipt.status,
|
|
264
|
+
blockNumber: receipt.blockNumber.toString(),
|
|
265
|
+
gasUsed: receipt.gasUsed.toString()
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
return { transactions };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/commands/launch.ts
|
|
272
|
+
var ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
273
|
+
var optionSchema2 = z3.object({
|
|
274
|
+
mode: z3.enum(["zrp", "standard"]).default("zrp").describe("Launch mode."),
|
|
275
|
+
chainId: z3.coerce.number().default(chains_default.baseSepolia.id).describe("Chain ID for the launch calls."),
|
|
276
|
+
rpcUrl: z3.string().optional().describe("RPC URL for read calls."),
|
|
277
|
+
account: address("account").optional().describe("Deployer address. Derived from the private key when executing."),
|
|
278
|
+
name: z3.string().describe("BToken name."),
|
|
279
|
+
symbol: z3.string().describe("BToken symbol."),
|
|
280
|
+
reserve: address("reserve").describe("Reserve token address."),
|
|
281
|
+
totalSupply: z3.string().describe("Total BToken supply in token units."),
|
|
282
|
+
initialPoolBtokens: z3.string().optional().describe("Initial BTokens deposited into the pool for standard launches, in token units."),
|
|
283
|
+
initialPoolReserves: z3.string().optional().describe("Initial reserve amount for standard launches."),
|
|
284
|
+
creator: address("creator").optional().describe("Creator address."),
|
|
285
|
+
feeRecipient: address("feeRecipient").optional().describe("Protocol fee recipient, defaults to creator."),
|
|
286
|
+
creatorFeePct: z3.string().default("50").describe("Creator fee percentage, for example 50 for 50%."),
|
|
287
|
+
swapFeePct: z3.string().default("1").describe("Swap fee percentage, for example 1 for 1%."),
|
|
288
|
+
salt: z3.string().optional().describe("Optional bytes32 salt."),
|
|
289
|
+
reserveDecimals: z3.coerce.number().default(18).describe("Reserve token decimals."),
|
|
290
|
+
execute: z3.boolean().default(false).describe("Execute the launch calls with a private key signer."),
|
|
291
|
+
privateKey: z3.string().optional().describe("Private key used with --execute. Falls back to BASELINE_PRIVATE_KEY."),
|
|
292
|
+
output: z3.string().optional().describe("Optional path to write JSON calls.")
|
|
293
|
+
});
|
|
294
|
+
var launchCommand = {
|
|
295
|
+
description: "Build wallet_sendCalls-compatible calls for a Baseline launch.",
|
|
296
|
+
options: optionSchema2,
|
|
297
|
+
async run(c) {
|
|
298
|
+
const artifact = await buildLaunchArtifact(c.options);
|
|
299
|
+
const result = {
|
|
300
|
+
...artifact,
|
|
301
|
+
calls: serializeCalls(artifact.calls),
|
|
302
|
+
...c.options.execute ? { execution: await executeLaunchArtifact(artifact, c.options) } : {}
|
|
303
|
+
};
|
|
304
|
+
if (c.options.output) {
|
|
305
|
+
await writeFile(c.options.output, `${JSON.stringify(result, null, 2)}
|
|
306
|
+
`);
|
|
307
|
+
}
|
|
308
|
+
return result;
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
async function buildLaunchArtifact(options) {
|
|
312
|
+
const chain = getChain(options.chainId);
|
|
313
|
+
const account = resolveAccount(options);
|
|
314
|
+
const reserve = options.reserve;
|
|
315
|
+
const creator = options.creator ?? account;
|
|
316
|
+
const feeRecipient = options.feeRecipient ?? creator;
|
|
317
|
+
const totalSupply = parseUnits(options.totalSupply, 18);
|
|
318
|
+
const initialPoolBTokens = resolveInitialPoolBTokens(options, totalSupply);
|
|
319
|
+
const salt = options.salt ? parseSalt(options.salt) : ZERO_BYTES32;
|
|
320
|
+
const launchInput = {
|
|
321
|
+
mode: options.mode,
|
|
322
|
+
name: options.name,
|
|
323
|
+
symbol: options.symbol,
|
|
324
|
+
reserve,
|
|
325
|
+
totalSupply,
|
|
326
|
+
initialPoolBTokens,
|
|
327
|
+
initialPoolReserves: options.initialPoolReserves ? parseUnits(options.initialPoolReserves, options.reserveDecimals) : 0n,
|
|
328
|
+
creator,
|
|
329
|
+
feeRecipient,
|
|
330
|
+
creatorFeePct: parsePctToWad(options.creatorFeePct),
|
|
331
|
+
swapFeePct: parsePctToWad(options.swapFeePct),
|
|
332
|
+
salt,
|
|
333
|
+
reserveDecimals: options.reserveDecimals
|
|
334
|
+
};
|
|
335
|
+
const publicClient = createPublicClient3({
|
|
336
|
+
chain,
|
|
337
|
+
transport: http3(options.rpcUrl)
|
|
338
|
+
});
|
|
339
|
+
const sdk = new BaselineSDK2(publicClient);
|
|
340
|
+
const bToken = await sdk.precomputeBTokenAddress({
|
|
341
|
+
name: launchInput.name,
|
|
342
|
+
symbol: launchInput.symbol,
|
|
343
|
+
totalSupply,
|
|
344
|
+
salt,
|
|
345
|
+
deployer: account
|
|
346
|
+
});
|
|
347
|
+
const calls = await sdk.calls.launch(launchInput, { account });
|
|
348
|
+
return {
|
|
349
|
+
chainId: options.chainId,
|
|
350
|
+
chain: chain.name,
|
|
351
|
+
account,
|
|
352
|
+
bToken,
|
|
353
|
+
calls
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function resolveAccount(options) {
|
|
357
|
+
if (options.account)
|
|
358
|
+
return options.account;
|
|
359
|
+
if (!options.execute) {
|
|
360
|
+
throw new Error("--account is required unless --execute is used.");
|
|
361
|
+
}
|
|
362
|
+
const privateKey = options.privateKey ?? process.env.BASELINE_PRIVATE_KEY;
|
|
363
|
+
if (!privateKey) {
|
|
364
|
+
throw new Error("--account is required when no --private-key or BASELINE_PRIVATE_KEY is set.");
|
|
365
|
+
}
|
|
366
|
+
return privateKeyToAccount2(parsePrivateKey(privateKey)).address;
|
|
367
|
+
}
|
|
368
|
+
function resolveInitialPoolBTokens(options, totalSupply) {
|
|
369
|
+
if (options.mode === "zrp") {
|
|
370
|
+
if (options.initialPoolBtokens) {
|
|
371
|
+
throw new Error("--initial-pool-btokens is not needed for zrp launches.");
|
|
372
|
+
}
|
|
373
|
+
return totalSupply;
|
|
374
|
+
}
|
|
375
|
+
if (!options.initialPoolBtokens) {
|
|
376
|
+
throw new Error("--initial-pool-btokens is required for standard launches.");
|
|
377
|
+
}
|
|
378
|
+
return parseUnits(options.initialPoolBtokens, 18);
|
|
379
|
+
}
|
|
380
|
+
function parseSalt(value) {
|
|
381
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {
|
|
382
|
+
throw new Error("Salt must be a bytes32 hex string.");
|
|
383
|
+
}
|
|
384
|
+
return value;
|
|
385
|
+
}
|
|
386
|
+
function parsePctToWad(value) {
|
|
387
|
+
const pct = parseUnits(value, 16);
|
|
388
|
+
if (pct < 0n || pct > 10n ** 18n) {
|
|
389
|
+
throw new Error(`Percentage must be between 0 and 100: ${value}`);
|
|
390
|
+
}
|
|
391
|
+
return pct;
|
|
392
|
+
}
|
|
393
|
+
async function executeLaunchArtifact(artifact, options) {
|
|
394
|
+
const chain = getChain(artifact.chainId);
|
|
395
|
+
const privateKey = options.privateKey ?? process.env.BASELINE_PRIVATE_KEY;
|
|
396
|
+
if (!privateKey) {
|
|
397
|
+
throw new Error("--private-key or BASELINE_PRIVATE_KEY is required when using --execute.");
|
|
398
|
+
}
|
|
399
|
+
return executeCalls({
|
|
400
|
+
chain,
|
|
401
|
+
calls: artifact.calls,
|
|
402
|
+
privateKey: parsePrivateKey(privateKey),
|
|
403
|
+
rpcUrl: options.rpcUrl,
|
|
404
|
+
expectedAccount: artifact.account
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/env.ts
|
|
409
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
410
|
+
import { dirname, resolve } from "node:path";
|
|
411
|
+
import { fileURLToPath } from "node:url";
|
|
412
|
+
var packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
413
|
+
var workspaceRoot = resolve(packageRoot, "../..");
|
|
414
|
+
var skillsGlob = resolve(packageRoot, "skills/*");
|
|
415
|
+
function loadCliEnv() {
|
|
416
|
+
for (const path of [
|
|
417
|
+
resolve(workspaceRoot, ".env"),
|
|
418
|
+
resolve(packageRoot, ".env")
|
|
419
|
+
]) {
|
|
420
|
+
loadEnv(path);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
function loadEnv(path) {
|
|
424
|
+
if (!existsSync(path))
|
|
425
|
+
return;
|
|
426
|
+
if (typeof process.loadEnvFile === "function") {
|
|
427
|
+
process.loadEnvFile(path);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
for (const line of readFileSync(path, "utf8").split(/\r?\n/)) {
|
|
431
|
+
const trimmed = line.trim();
|
|
432
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
433
|
+
continue;
|
|
434
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(trimmed);
|
|
435
|
+
if (!match)
|
|
436
|
+
continue;
|
|
437
|
+
const key = match[1];
|
|
438
|
+
const rawValue = match[2];
|
|
439
|
+
if (!key || rawValue === undefined)
|
|
440
|
+
continue;
|
|
441
|
+
const value = rawValue.replace(/^['"]|['"]$/g, "");
|
|
442
|
+
process.env[key] ??= value;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/index.ts
|
|
447
|
+
loadCliEnv();
|
|
448
|
+
var cli = Cli.create("baseline", {
|
|
449
|
+
version: "0.1.0",
|
|
450
|
+
description: "Baseline Markets CLI",
|
|
451
|
+
sync: {
|
|
452
|
+
include: [skillsGlob],
|
|
453
|
+
suggestions: [
|
|
454
|
+
"build launch calls for a new Baseline token",
|
|
455
|
+
"output launch calls as JSON for wallet_sendCalls"
|
|
456
|
+
]
|
|
457
|
+
}
|
|
458
|
+
}).command("launch", launchCommand).command("info", infoCommand);
|
|
459
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
460
|
+
await cli.serve();
|
|
461
|
+
}
|
|
462
|
+
export {
|
|
463
|
+
cli
|
|
464
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@baseline-markets/cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/0xBaseline/baseline-mono.git",
|
|
8
|
+
"directory": "packages/cli"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"baseline": "dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"skills"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
".": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"dev": "bun src/index.ts",
|
|
23
|
+
"build": "bun build src/index.ts --target=node --outdir=dist --external @baseline-markets/sdk --external incur --external viem",
|
|
24
|
+
"prepublishOnly": "bun run build",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "bun test",
|
|
27
|
+
"test:integration": "bun test tests/*.integration.test.ts"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@baseline-markets/sdk": "^1.1.0",
|
|
31
|
+
"incur": "^0.4.8",
|
|
32
|
+
"viem": "^2.31.6"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@baseline/chains": "workspace:*",
|
|
36
|
+
"@types/bun": "latest",
|
|
37
|
+
"typescript": "^5.8.3"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aeon-baseline
|
|
3
|
+
description: Execute a Baseline launch call artifact through an Aeon operator workflow.
|
|
4
|
+
var: ""
|
|
5
|
+
tags: [crypto, onchain]
|
|
6
|
+
capabilities: [external_api, writes_external_host, onchain_writes, sends_notifications]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
> **${var}** - Path to a saved `baseline launch` JSON artifact, or empty
|
|
10
|
+
> when `run.vars.launchArtifact` already contains the artifact object. If
|
|
11
|
+
> neither is available, notify `LAUNCH_BASELINE_NO_ARTIFACT` and stop.
|
|
12
|
+
|
|
13
|
+
Today is ${today}. Execute a Baseline launch call artifact through the
|
|
14
|
+
configured Aeon operator surface without inventing calldata, signers, or wallet
|
|
15
|
+
policy.
|
|
16
|
+
|
|
17
|
+
## Required Config
|
|
18
|
+
|
|
19
|
+
- `AEON_RUN_URL` is required only when dispatching this skill through the
|
|
20
|
+
repository CLI executor.
|
|
21
|
+
- `AEON_AUTH_TOKEN` is optional and is sent as `Authorization: Bearer ...` by
|
|
22
|
+
the CLI executor when configured.
|
|
23
|
+
- The launch artifact must already be produced by `baseline launch`.
|
|
24
|
+
- Aeon execution is Base mainnet only in v1.
|
|
25
|
+
- Register this skill in an Aeon instance by copying this folder under
|
|
26
|
+
`skills/`, running `./generate-skills-json`, and adding an `aeon.yml` entry
|
|
27
|
+
with `enabled: false` and `schedule: "manual"` until an operator explicitly
|
|
28
|
+
enables it.
|
|
29
|
+
|
|
30
|
+
## CLI Artifact Contract
|
|
31
|
+
|
|
32
|
+
`baseline launch` builds and validates the canonical call artifact. The
|
|
33
|
+
`--output` file is the source of truth:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"chainId": 8453,
|
|
38
|
+
"chain": "base",
|
|
39
|
+
"account": "0xAeonOperatorWallet",
|
|
40
|
+
"bToken": "0x...",
|
|
41
|
+
"calls": [{ "to": "0x...", "data": "0x...", "value": "0x0" }]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Required Aeon launch inputs:
|
|
46
|
+
|
|
47
|
+
- `--mode zrp` or `--mode standard`
|
|
48
|
+
- `--chain-id 8453`
|
|
49
|
+
- `--account "$AEON_OPERATOR_WALLET"`
|
|
50
|
+
- `--name "$TOKEN_NAME"`
|
|
51
|
+
- `--symbol "$TOKEN_SYMBOL"`
|
|
52
|
+
- `--reserve 0x4200000000000000000000000000000000000006`
|
|
53
|
+
- `--total-supply "$TOTAL_SUPPLY"`
|
|
54
|
+
- `--initial-pool-btokens "$POOL_BTOKENS"` for `standard`
|
|
55
|
+
- `--initial-pool-reserves "$RESERVE_SEED"` for `standard`
|
|
56
|
+
- `--output .context/launches/aeon-launch.json`
|
|
57
|
+
|
|
58
|
+
Key optional controls:
|
|
59
|
+
|
|
60
|
+
- Fees: `--swap-fee-pct` and `--creator-fee-pct`.
|
|
61
|
+
- Parties and salt: `--creator`, `--fee-recipient`, and `--salt`.
|
|
62
|
+
|
|
63
|
+
Build the handoff artifact before running this skill:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
baseline launch \
|
|
67
|
+
--mode zrp \
|
|
68
|
+
--chain-id 8453 \
|
|
69
|
+
--account "$AEON_OPERATOR_WALLET" \
|
|
70
|
+
--name "$TOKEN_NAME" \
|
|
71
|
+
--symbol "$TOKEN_SYMBOL" \
|
|
72
|
+
--reserve 0x4200000000000000000000000000000000000006 \
|
|
73
|
+
--total-supply "$TOTAL_SUPPLY" \
|
|
74
|
+
--output .context/launches/aeon-launch.json
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Before Aeon execution, verify `chainId`, `account`, call count, call order,
|
|
78
|
+
allowed targets, and selected mode economics. `zrp` artifacts use
|
|
79
|
+
three calls and all BTokens in the pool. `standard` artifacts use four calls,
|
|
80
|
+
a nonzero reserve seed, and `createPool`.
|
|
81
|
+
|
|
82
|
+
## Steps
|
|
83
|
+
|
|
84
|
+
1. **Load the artifact.** If `run.vars.launchArtifact` exists, use it.
|
|
85
|
+
Otherwise read the JSON file path from `${var}`. If both are absent, run:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
./notify "LAUNCH_BASELINE_NO_ARTIFACT: provide var=<path-to-launch-artifact.json> or run.vars.launchArtifact"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then stop.
|
|
92
|
+
|
|
93
|
+
2. **Validate the artifact.** Confirm:
|
|
94
|
+
|
|
95
|
+
- `chainId` is `8453`.
|
|
96
|
+
- `account` is present and is the expected Aeon operator wallet.
|
|
97
|
+
- `calls` is an array with exactly three or four items.
|
|
98
|
+
- Every call has `to`, `data`, and `value`.
|
|
99
|
+
|
|
100
|
+
3. **Validate transaction shape.** Confirm the call order matches the selected
|
|
101
|
+
mode:
|
|
102
|
+
|
|
103
|
+
- `zrp`: Relay `createBToken`, BToken `approve`, Relay
|
|
104
|
+
`createPoolFromInvariant`.
|
|
105
|
+
- `standard`: Relay `createBToken`, BToken `approve`, reserve `approve`, Relay
|
|
106
|
+
`createPool`.
|
|
107
|
+
|
|
108
|
+
Reject any artifact whose targets are outside the Baseline Relay, precomputed
|
|
109
|
+
BToken, and reserve token.
|
|
110
|
+
|
|
111
|
+
4. **Respect the executor boundary.** Do not sign directly, do not ask for a
|
|
112
|
+
private key, and do not rebuild calldata by hand. Use the artifact calls
|
|
113
|
+
exactly as produced by the CLI or abort with a notification explaining the
|
|
114
|
+
mismatch.
|
|
115
|
+
|
|
116
|
+
5. **Submit through the configured Aeon operator workflow.** If this skill is
|
|
117
|
+
running inside Aeon with a wallet-capable operator surface, submit the
|
|
118
|
+
ordered Base mainnet calls according to that operator's configured wallet
|
|
119
|
+
policy. If no wallet execution surface is configured, emit a handoff
|
|
120
|
+
notification and stop without broadcasting.
|
|
121
|
+
|
|
122
|
+
6. **Verify on-chain state.** After a successful run, perform read-only checks:
|
|
123
|
+
|
|
124
|
+
- BToken code is non-empty.
|
|
125
|
+
- Maker initialization is true.
|
|
126
|
+
- Reserve equals Base WETH.
|
|
127
|
+
- Creator and fee recipient match the artifact expectations.
|
|
128
|
+
- For `zrp`, total reserves and deployer BToken balance are `0`.
|
|
129
|
+
|
|
130
|
+
7. **Log.** Append to `memory/logs/${today}.md`:
|
|
131
|
+
|
|
132
|
+
```markdown
|
|
133
|
+
## aeon-baseline
|
|
134
|
+
- Artifact: ARTIFACT_PATH_OR_INLINE
|
|
135
|
+
- Chain ID: 8453
|
|
136
|
+
- Account: ACCOUNT
|
|
137
|
+
- Status: SUBMITTED | HANDOFF_READY | VERIFIED | REJECTED
|
|
138
|
+
- Transaction hashes: HASHES_OR_NONE
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
8. **Notify.** Send a notification under 4000 characters:
|
|
142
|
+
|
|
143
|
+
```text
|
|
144
|
+
Baseline launch: STATUS
|
|
145
|
+
Account: ACCOUNT
|
|
146
|
+
Txs: HASHES_OR_HANDOFF
|
|
147
|
+
Next: verification summary or rejection reason
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Sandbox Note
|
|
151
|
+
|
|
152
|
+
Authenticated wallet or run APIs may not be reachable from the Claude sandbox.
|
|
153
|
+
If secrets are unavailable, do not fail noisily or fabricate execution. Notify
|
|
154
|
+
`LAUNCH_BASELINE_HANDOFF_READY`, write the handoff details to memory, and stop.
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bankr-baseline
|
|
3
|
+
description: Build Baseline launch call artifacts and submit them with Bankr Wallet API
|
|
4
|
+
tags: [crypto, baseline, token, erc20]
|
|
5
|
+
version: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Bankr Baseline
|
|
9
|
+
|
|
10
|
+
Use this skill when a user wants an agent to plan and deploy a Baseline token
|
|
11
|
+
with this repository's `baseline` CLI and Bankr's Wallet API.
|
|
12
|
+
|
|
13
|
+
## Skill Contract
|
|
14
|
+
|
|
15
|
+
| Field | Requirement |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Purpose | Build, review, and submit explicit Baseline launch calls. |
|
|
18
|
+
| Supported chain | Confirmed Bankr execution uses Base mainnet, chain ID `8453`. |
|
|
19
|
+
| Pending validation | Base Sepolia `84532` needs authenticated Wallet API validation before Bankr execution. |
|
|
20
|
+
| Planner | The local `baseline` CLI is the launch calldata builder. |
|
|
21
|
+
| Protocol surface | The CLI uses Baseline SDK/protocol helpers for economics, addresses, and calldata. |
|
|
22
|
+
| Wallet executor | Bankr provides wallet identity, signing, and transaction submission only. |
|
|
23
|
+
| Allowed Bankr endpoints | `GET /wallet/me` and `POST /wallet/submit`. |
|
|
24
|
+
| Canonical artifact | `baseline launch` call artifact with `{ chainId, chain, account, bToken, calls }`. |
|
|
25
|
+
| Hard stops | No private keys, Bankr native launches, Agent API prompts, or hand-built calldata. |
|
|
26
|
+
|
|
27
|
+
Base MCP remains the confirmed Sepolia test executor in this repository. Bankr
|
|
28
|
+
Wallet API docs document explicit transaction submission by `chainId`, but do
|
|
29
|
+
not currently document Base Sepolia `84532` as supported. Do not use Bankr for
|
|
30
|
+
Base Sepolia execution until an authenticated validation run proves support.
|
|
31
|
+
|
|
32
|
+
## Protocol Constants
|
|
33
|
+
|
|
34
|
+
| Chain | Chain ID | Reserve | Use |
|
|
35
|
+
|---|---:|---|---|
|
|
36
|
+
| Base Sepolia | `84532` | `0xB85885897D297000A74eA2e4711C3Ca729461ABC` | Pending Bankr validation. |
|
|
37
|
+
| Base mainnet | `8453` | `0x4200000000000000000000000000000000000006` | Approved production launches. |
|
|
38
|
+
|
|
39
|
+
Baseline Relay proxy on both profiles:
|
|
40
|
+
`0xc81Fd894C0acE037d133aF4886550aC8133568E8`.
|
|
41
|
+
|
|
42
|
+
## Required Setup
|
|
43
|
+
|
|
44
|
+
- `BANKR_API_KEY` must be set only in the local execution environment or secret
|
|
45
|
+
manager.
|
|
46
|
+
- Optional: `BANKR_API_BASE`, defaulting to `https://api.bankr.bot`.
|
|
47
|
+
- The Bankr key must have Wallet API write access enabled and must not be
|
|
48
|
+
read-only.
|
|
49
|
+
- Raw `/wallet/submit` cannot be used when the key has `allowedRecipients`
|
|
50
|
+
restrictions, because Bankr blocks raw submissions for those keys.
|
|
51
|
+
- The Bankr EVM wallet returned by `/wallet/me` is the Baseline launch
|
|
52
|
+
`account` unless the user explicitly chooses another supported policy.
|
|
53
|
+
|
|
54
|
+
## CLI Artifact Contract
|
|
55
|
+
|
|
56
|
+
The CLI is the only Baseline launch calldata builder in this workflow. It
|
|
57
|
+
collects launch inputs, applies defaults, calls SDK-backed protocol helpers,
|
|
58
|
+
builds ordered raw calls, and writes a JSON artifact. It does not custody keys
|
|
59
|
+
or sign transactions.
|
|
60
|
+
|
|
61
|
+
`baseline launch` writes the canonical artifact:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"chainId": 8453,
|
|
66
|
+
"chain": "base",
|
|
67
|
+
"account": "0xBankrWallet",
|
|
68
|
+
"bToken": "0x...",
|
|
69
|
+
"calls": [{ "to": "0x...", "data": "0x...", "value": "0x0" }]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Required Bankr launch flags:
|
|
74
|
+
|
|
75
|
+
| Flag | Required value | Description |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `--mode` | `zrp` by default, `standard` when a reserve seed is required | Selects the Baseline launch path. |
|
|
78
|
+
| `--chain-id` | `8453` | Keeps Bankr on the confirmed Base mainnet execution chain. |
|
|
79
|
+
| `--account` | `"$BANKR_WALLET"` | Uses the EVM wallet returned by Bankr `/wallet/me`. |
|
|
80
|
+
| `--name` | `"$TOKEN_NAME"` | Sets the BToken name passed to the Baseline Relay. |
|
|
81
|
+
| `--symbol` | `"$TOKEN_SYMBOL"` | Sets the BToken symbol passed to the Baseline Relay. |
|
|
82
|
+
| `--reserve` | Base mainnet WETH | Uses the confirmed reserve token. |
|
|
83
|
+
| `--total-supply` | Launch-specific supply | Sets human-unit total supply. |
|
|
84
|
+
| `--initial-pool-btokens` | Required for `standard`; omit for `zrp` | Sets the pool BToken amount while leaving circulating supply. |
|
|
85
|
+
| `--initial-pool-reserves` | Required for `standard` | Sets the reserve seed. |
|
|
86
|
+
| `--output` | `.context/launches/bankr-launch.json` | Saves the artifact under `.context/`. |
|
|
87
|
+
|
|
88
|
+
Important optional launch flags:
|
|
89
|
+
|
|
90
|
+
| Category | Flags | Description |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| Fees | `--swap-fee-pct`, `--creator-fee-pct` | Defaults are `1%` and `50%`; swap fee protocol bounds are `0.15%` to `50%`. |
|
|
93
|
+
| Parties | `--creator`, `--fee-recipient` | Creator defaults to `account`; fee recipient defaults to creator. |
|
|
94
|
+
| Salt | `--salt` | Sets deterministic BToken salt; empty input uses zero `bytes32`. |
|
|
95
|
+
|
|
96
|
+
## Default Launch Profile
|
|
97
|
+
|
|
98
|
+
### ZRP
|
|
99
|
+
|
|
100
|
+
| Setting | Default | Notes |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| Mode | `zrp` | Default launch path. |
|
|
103
|
+
| Chain ID | `8453` for Bankr | Bankr remains Base mainnet only. |
|
|
104
|
+
| Supply | `100B` | Human-unit total supply when not overridden. |
|
|
105
|
+
| Pool BTokens | Derived from `totalSupply` | Deployer BToken balance is `0`. |
|
|
106
|
+
| Pool reserves | `0` | No reserve approval is expected. |
|
|
107
|
+
| Reserve | Base mainnet WETH | `0x4200000000000000000000000000000000000006`. |
|
|
108
|
+
| Swap fee | `1%` | Must stay within protocol bounds. |
|
|
109
|
+
| Creator fee share | `50%` | Creator share of pool fees. |
|
|
110
|
+
| Creator | Bankr EVM wallet | Override only when explicitly requested. |
|
|
111
|
+
| Fee recipient | Creator | Override only when explicitly requested. |
|
|
112
|
+
| `createHook` | `true` | Matches the current SDK launch params. |
|
|
113
|
+
|
|
114
|
+
### Standard
|
|
115
|
+
|
|
116
|
+
| Setting | Default | Notes |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| Mode | `standard` | Explicit standard launch path. |
|
|
119
|
+
| Chain ID | `8453` for Bankr | Bankr remains Base mainnet only. |
|
|
120
|
+
| Pool BTokens | User supplied | Must leave circulating supply. |
|
|
121
|
+
| Pool reserves | User supplied | Must be nonzero. |
|
|
122
|
+
| Pool creation | `createPool` | Uses the `createPool` Relay flow. |
|
|
123
|
+
| Shared fees and parties | Same as `zrp` | Override only with explicit fee, creator, or recipient flags. |
|
|
124
|
+
| `createHook` | `true` | Matches the current SDK launch params. |
|
|
125
|
+
|
|
126
|
+
## Baseline Launch Call Sequence
|
|
127
|
+
|
|
128
|
+
The Baseline protocol launch is represented as an ordered call sequence inside
|
|
129
|
+
the CLI-generated artifact. Bankr does not decide this sequence. Bankr only
|
|
130
|
+
identifies the wallet and signs/submits the explicit calls that the CLI
|
|
131
|
+
produces.
|
|
132
|
+
|
|
133
|
+
For `zrp`, the sequence is:
|
|
134
|
+
|
|
135
|
+
| Order | Step | Transaction purpose |
|
|
136
|
+
|---|---|---|
|
|
137
|
+
| 1 | `createBToken` | Deploy the planned BToken through the Baseline Relay. |
|
|
138
|
+
| 2 | BToken `approve` | Approve the Baseline Relay to move the full BToken supply for pool creation. |
|
|
139
|
+
| 3 | `createPoolFromInvariant` | Create the pool from the computed invariant and planned params. |
|
|
140
|
+
|
|
141
|
+
For `standard`, the sequence is:
|
|
142
|
+
|
|
143
|
+
| Order | Step | Transaction purpose |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| 1 | `createBToken` | Deploy the planned BToken through the Baseline Relay. |
|
|
146
|
+
| 2 | BToken `approve` | Approve the Baseline Relay to move the planned BToken pool allocation. |
|
|
147
|
+
| 3 | Reserve `approve` | Approve the Baseline Relay to move the planned reserve seed. |
|
|
148
|
+
| 4 | `createPool` | Create the pool with standard params, fees, creator, and fee recipient. |
|
|
149
|
+
|
|
150
|
+
These calls are dependent. If a live run partially completes, do not replay the
|
|
151
|
+
full sequence blindly. Verify the last completed on-chain step and recover from
|
|
152
|
+
that exact state.
|
|
153
|
+
|
|
154
|
+
## Execution Plan
|
|
155
|
+
|
|
156
|
+
1. Resolve the Bankr EVM wallet with `/wallet/me`.
|
|
157
|
+
2. Use that wallet as `--account` for the local CLI artifact builder.
|
|
158
|
+
3. Confirm the user explicitly approved a Bankr Base mainnet run.
|
|
159
|
+
4. Run `baseline launch --chain-id 8453` and save the artifact.
|
|
160
|
+
5. Review the saved artifact: `chainId`, `account`, ordered call count, call
|
|
161
|
+
targets, and call data.
|
|
162
|
+
6. Submit each artifact call through Bankr Wallet API `/wallet/submit` in
|
|
163
|
+
order. Wait for each submission result before sending the next dependent
|
|
164
|
+
call.
|
|
165
|
+
7. Verify on-chain state and store one-off run notes under `.context/`.
|
|
166
|
+
|
|
167
|
+
## Commands
|
|
168
|
+
|
|
169
|
+
Read the Bankr wallet identity:
|
|
170
|
+
|
|
171
|
+
```sh
|
|
172
|
+
BANKR_API_BASE="${BANKR_API_BASE:-https://api.bankr.bot}"
|
|
173
|
+
curl -s "$BANKR_API_BASE/wallet/me" \
|
|
174
|
+
-H "X-API-Key: $BANKR_API_KEY"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Build a Bankr Base mainnet artifact with the local CLI:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
baseline launch \
|
|
181
|
+
--mode zrp \
|
|
182
|
+
--chain-id 8453 \
|
|
183
|
+
--account "$BANKR_WALLET" \
|
|
184
|
+
--name "$TOKEN_NAME" \
|
|
185
|
+
--symbol "$TOKEN_SYMBOL" \
|
|
186
|
+
--reserve 0x4200000000000000000000000000000000000006 \
|
|
187
|
+
--total-supply "$TOTAL_SUPPLY" \
|
|
188
|
+
--output .context/launches/bankr-launch.json
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
For a `standard` launch, include `--initial-pool-reserves "$RESERVE_SEED"` and
|
|
192
|
+
set `--initial-pool-btokens` below `--total-supply`.
|
|
193
|
+
|
|
194
|
+
Submit each call in order through Bankr:
|
|
195
|
+
|
|
196
|
+
```http
|
|
197
|
+
POST /wallet/submit
|
|
198
|
+
X-API-Key: $BANKR_API_KEY
|
|
199
|
+
Content-Type: application/json
|
|
200
|
+
|
|
201
|
+
{
|
|
202
|
+
"chainId": 8453,
|
|
203
|
+
"to": "<call.to>",
|
|
204
|
+
"data": "<call.data>",
|
|
205
|
+
"value": "<call.value>"
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Review Checklist
|
|
210
|
+
|
|
211
|
+
Before any live submission, confirm:
|
|
212
|
+
|
|
213
|
+
- The user explicitly authorized Bankr live execution on Base mainnet.
|
|
214
|
+
- `BANKR_API_KEY` is set for a live run and is not exposed in tracked files.
|
|
215
|
+
- `/wallet/me` returns an EVM wallet address.
|
|
216
|
+
- `artifact.chainId` is `8453`.
|
|
217
|
+
- `artifact.account` equals the Bankr EVM wallet unless the user explicitly
|
|
218
|
+
chose another supported policy.
|
|
219
|
+
- The transaction order and count match the selected CLI mode.
|
|
220
|
+
- Transaction targets are limited to the Baseline Relay, precomputed BToken,
|
|
221
|
+
and reserve token.
|
|
222
|
+
- `zrp` artifacts use all BTokens in the pool and no reserve approval.
|
|
223
|
+
- `standard` artifacts include the intended reserve seed and circulating supply.
|
|
224
|
+
|
|
225
|
+
## Verification
|
|
226
|
+
|
|
227
|
+
After a successful live run, perform read-only verification:
|
|
228
|
+
|
|
229
|
+
- BToken code is non-empty.
|
|
230
|
+
- `bLens.getMaker(bToken).initialized` is true.
|
|
231
|
+
- `bLens.reserve(bToken)` equals the planned chain reserve.
|
|
232
|
+
- `bLens.creator(bToken)` equals the planned creator.
|
|
233
|
+
- `bLens.poolFeeRecipient(bToken)` equals the planned fee recipient.
|
|
234
|
+
- For `zrp`, total reserves and deployer BToken balance are both `0`.
|
|
235
|
+
- For `standard`, deployer BToken balance matches the planned circulating
|
|
236
|
+
allocation, allowing for integer division.
|
|
237
|
+
|
|
238
|
+
## Rejection Rules
|
|
239
|
+
|
|
240
|
+
Stop before live submission if:
|
|
241
|
+
|
|
242
|
+
- The user has not explicitly authorized Bankr live execution.
|
|
243
|
+
- Base mainnet execution is implied but not explicitly approved.
|
|
244
|
+
- `BANKR_API_KEY` is missing for a live run.
|
|
245
|
+
- `/wallet/me` does not return an EVM wallet address.
|
|
246
|
+
- The artifact is not for chain ID `8453`.
|
|
247
|
+
- The prepared transaction order or count differs from the selected CLI mode.
|
|
248
|
+
- Any requested flow involves raw private keys, seed phrases, local production
|
|
249
|
+
signing, Bankr native launch endpoints, or Agent API prompts.
|
|
250
|
+
|
|
251
|
+
## Troubleshooting
|
|
252
|
+
|
|
253
|
+
- `403`: confirm Wallet API write access, read-only mode, IP allowlist, and
|
|
254
|
+
absence of `allowedRecipients` restrictions.
|
|
255
|
+
- Base Sepolia requested: use Base MCP for the confirmed Sepolia path, or run a
|
|
256
|
+
separate authenticated Bankr validation task before enabling Bankr Sepolia.
|
|
257
|
+
- Missing transaction hash: treat the phase as ambiguous and perform read-only
|
|
258
|
+
on-chain verification before retrying.
|
|
259
|
+
- Partial failure: do not replay the full sequence blindly. Recover from the
|
|
260
|
+
exact last verified phase.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: base-mcp-baseline
|
|
3
|
+
description: Vendors the Baseline plugin for Base MCP so agents can launch Baseline tokens with the Baseline CLI and Base Account approval. Use when a user wants to use Base MCP, Base Account, send_calls, or the Baseline CLI to prepare and submit a Baseline token launch.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Baseline Base MCP
|
|
7
|
+
|
|
8
|
+
This skill packages the Baseline Base MCP plugin with `@baseline-markets/cli`.
|
|
9
|
+
The plugin file is the source of truth; do not duplicate or improvise the launch
|
|
10
|
+
workflow here.
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
1. If the installed Base MCP skill already includes a native `baseline` plugin,
|
|
15
|
+
use that native plugin.
|
|
16
|
+
2. Otherwise, read and follow [plugins/baseline.md](plugins/baseline.md).
|
|
17
|
+
3. Use the local `baseline` binary when available; otherwise use the `npx`
|
|
18
|
+
command documented in the plugin.
|
|
19
|
+
|
|
20
|
+
## Boundary
|
|
21
|
+
|
|
22
|
+
- The installed Base MCP skill/server is still required.
|
|
23
|
+
- The Baseline CLI prepares unsigned launch call artifacts.
|
|
24
|
+
- Base MCP provides wallet identity, Base Account approval, submission, and
|
|
25
|
+
request-status polling.
|
|
26
|
+
- Do not use `baseline launch --execute` in the Base MCP flow.
|
|
27
|
+
- Do not ask for, load, print, or use a private key.
|
|
28
|
+
|
|
29
|
+
## Distribution
|
|
30
|
+
|
|
31
|
+
This wrapper exists so users who discover Baseline through the CLI can install
|
|
32
|
+
the same Base MCP plugin instructions before the plugin is available natively in
|
|
33
|
+
their Base MCP skill bundle.
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Baseline Plugin"
|
|
3
|
+
description: "Launch Baseline tokens with the Baseline CLI, then submit unsigned calls through Base MCP send_calls."
|
|
4
|
+
tags: [token-launches, liquidity]
|
|
5
|
+
name: baseline
|
|
6
|
+
version: 0.1.0
|
|
7
|
+
integration: cli-only
|
|
8
|
+
chains: [base, base-sepolia]
|
|
9
|
+
requires:
|
|
10
|
+
shell: required
|
|
11
|
+
allowlist: []
|
|
12
|
+
externalMcp: null
|
|
13
|
+
cliPackage: "npx @baseline-markets/cli@latest"
|
|
14
|
+
auth: none
|
|
15
|
+
risk: [irreversible, local-exec, low-liquidity]
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Baseline Plugin
|
|
19
|
+
|
|
20
|
+
> [!IMPORTANT]
|
|
21
|
+
> Run Base MCP onboarding first (defined by the installed Base MCP SKILL.md). This plugin requires a shell-capable harness and a connected Base Account.
|
|
22
|
+
|
|
23
|
+
## Overview
|
|
24
|
+
|
|
25
|
+
Baseline is an onchain AMM for leveraged tokens. This plugin launches a
|
|
26
|
+
Baseline token on Base or Base Sepolia by running the Baseline CLI to prepare
|
|
27
|
+
unsigned launch calls, then submitting those calls through Base MCP
|
|
28
|
+
`send_calls` for Base Account approval and execution.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
No additional MCP server is required. The plugin shells out to the Baseline CLI
|
|
33
|
+
for each prepare step.
|
|
34
|
+
|
|
35
|
+
Use an installed CLI when available:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
baseline launch --help
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Otherwise invoke the package with `npx`:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
npx @baseline-markets/cli@latest launch --help
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Surface Routing
|
|
48
|
+
|
|
49
|
+
| Capability | Shell-capable surfaces | Shell-less / chat-only surfaces |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| Build launch calldata | Run `baseline launch` or `npx @baseline-markets/cli@latest launch`. | Stop. This plugin is CLI-only and must not use `web_request`, user-paste, or hand-built calldata as a workaround. |
|
|
52
|
+
| Submit prepared calls | Use Base MCP `send_calls`. | Stop unless the surface exposes both Base MCP tools and a way to run the CLI. |
|
|
53
|
+
| Check request status | Use Base MCP `get_request_status` after the user approves in Base Account. | Stop unless the pending request came from a supported CLI prepare flow. |
|
|
54
|
+
|
|
55
|
+
## Commands
|
|
56
|
+
|
|
57
|
+
`baseline launch` writes an unsigned call artifact:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"chainId": 84532,
|
|
62
|
+
"chain": "base-sepolia",
|
|
63
|
+
"account": "0xBaseAccount",
|
|
64
|
+
"bToken": "0xBToken",
|
|
65
|
+
"calls": [
|
|
66
|
+
{ "to": "0xTarget", "data": "0xCalldata", "value": "0x0" }
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Default Base Sepolia zero-reserve launch:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
baseline launch \
|
|
75
|
+
--mode zrp \
|
|
76
|
+
--chain-id 84532 \
|
|
77
|
+
--account "$BASE_ACCOUNT" \
|
|
78
|
+
--name "$TOKEN_NAME" \
|
|
79
|
+
--symbol "$TOKEN_SYMBOL" \
|
|
80
|
+
--reserve 0xB85885897D297000A74eA2e4711C3Ca729461ABC \
|
|
81
|
+
--total-supply "$TOTAL_SUPPLY" \
|
|
82
|
+
--output .context/launches/baseline-launch.json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Standard launch with reserve liquidity:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
baseline launch \
|
|
89
|
+
--mode standard \
|
|
90
|
+
--chain-id 84532 \
|
|
91
|
+
--account "$BASE_ACCOUNT" \
|
|
92
|
+
--name "$TOKEN_NAME" \
|
|
93
|
+
--symbol "$TOKEN_SYMBOL" \
|
|
94
|
+
--reserve 0xB85885897D297000A74eA2e4711C3Ca729461ABC \
|
|
95
|
+
--total-supply "$TOTAL_SUPPLY" \
|
|
96
|
+
--initial-pool-btokens "$POOL_BTOKENS" \
|
|
97
|
+
--initial-pool-reserves "$RESERVE_SEED" \
|
|
98
|
+
--output .context/launches/baseline-launch.json
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Base mainnet uses `--chain-id 8453` and WETH reserve
|
|
102
|
+
`0x4200000000000000000000000000000000000006`. Treat mainnet as production and
|
|
103
|
+
confirm the user explicitly requested it before preparing calls.
|
|
104
|
+
|
|
105
|
+
Do not pass `--execute` or `--private-key` in this plugin flow. Base MCP is the
|
|
106
|
+
only submission path.
|
|
107
|
+
|
|
108
|
+
## Orchestration
|
|
109
|
+
|
|
110
|
+
### Launch
|
|
111
|
+
|
|
112
|
+
1. Complete Base MCP onboarding and confirm Base MCP tools are available.
|
|
113
|
+
2. Call `get_wallets`, confirm the selected chain is in `supportedChains`, and
|
|
114
|
+
use the in-session Base Account address as `BASE_ACCOUNT`. If the Base
|
|
115
|
+
Account is not in session, stop and ask the user to reconnect Base MCP.
|
|
116
|
+
3. Gather token name, symbol, total supply, launch mode, and chain. Default to
|
|
117
|
+
Base Sepolia `84532` and `zrp` unless the user explicitly chooses otherwise.
|
|
118
|
+
4. For `standard`, require both `POOL_BTOKENS` and a nonzero `RESERVE_SEED`.
|
|
119
|
+
`POOL_BTOKENS` must be less than `TOTAL_SUPPLY` so some supply remains
|
|
120
|
+
circulating.
|
|
121
|
+
5. Run `baseline launch` with `--output`. If the CLI exits nonzero, fix inputs
|
|
122
|
+
and rerun; do not salvage partial output.
|
|
123
|
+
6. Parse the artifact JSON and validate it before submission:
|
|
124
|
+
- `account` equals the connected Base Account.
|
|
125
|
+
- `chainId` is `84532` or `8453`.
|
|
126
|
+
- `chain` is `base-sepolia` or `base`.
|
|
127
|
+
- `bToken` is a valid address.
|
|
128
|
+
- `calls` is an ordered array and every call has `to`, `data`, and `value`.
|
|
129
|
+
- No `execution` field is present.
|
|
130
|
+
- `zrp` has three calls; `standard` has four calls.
|
|
131
|
+
7. Submit the calls through `send_calls` as described in `## Submission`.
|
|
132
|
+
8. Show the returned `approvalUrl` as an "Approve Transaction" link and open it
|
|
133
|
+
with the local shell when the harness supports that.
|
|
134
|
+
9. Wait for the user to confirm they approved in Base Account, then call
|
|
135
|
+
`get_request_status(requestId)`. If it is still `pending`, retry with a
|
|
136
|
+
short delay; never report success until the request is `completed`.
|
|
137
|
+
10. After completion, run
|
|
138
|
+
`baseline info "$BTOKEN" --chain-id "$CHAIN_ID"` using the artifact
|
|
139
|
+
`bToken` and `chainId`.
|
|
140
|
+
|
|
141
|
+
## Submission
|
|
142
|
+
|
|
143
|
+
Submit with Base MCP `send_calls`.
|
|
144
|
+
|
|
145
|
+
Map the artifact exactly:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"chain": "base-sepolia",
|
|
150
|
+
"calls": [
|
|
151
|
+
{ "to": "0xTarget", "data": "0xCalldata", "value": "0x0" }
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Use `artifact.chain` directly. Preserve call order and do not edit calldata. Do
|
|
157
|
+
not include `artifact.account` in the `send_calls` payload; Base MCP uses the
|
|
158
|
+
connected Base Account session for approval and execution.
|
|
159
|
+
|
|
160
|
+
Expected call sequences:
|
|
161
|
+
|
|
162
|
+
- `zrp`: Relay `createBToken`, BToken `approve`, Relay
|
|
163
|
+
`createPoolFromInvariant`.
|
|
164
|
+
- `standard`: Relay `createBToken`, BToken `approve`, reserve `approve`, Relay
|
|
165
|
+
`createPool`.
|
|
166
|
+
|
|
167
|
+
Any `send_calls` approval URL follows the Base MCP approval flow: show an
|
|
168
|
+
"Approve Transaction" link, open it from shell-capable harnesses, wait for the
|
|
169
|
+
user to approve in Base Account, then poll `get_request_status`.
|
|
170
|
+
|
|
171
|
+
## Example Prompts
|
|
172
|
+
|
|
173
|
+
Launch a Base Sepolia test token:
|
|
174
|
+
|
|
175
|
+
1. Get the Base Account with `get_wallets`.
|
|
176
|
+
2. Run the `zrp` Base Sepolia `baseline launch` command with the requested name,
|
|
177
|
+
symbol, and supply.
|
|
178
|
+
3. Validate the artifact and call count.
|
|
179
|
+
4. Submit `artifact.calls` to `send_calls` with `chain: artifact.chain`.
|
|
180
|
+
5. Wait for approval, poll status, then run `baseline info`.
|
|
181
|
+
|
|
182
|
+
Launch a standard token with seed liquidity:
|
|
183
|
+
|
|
184
|
+
1. Require `POOL_BTOKENS` and `RESERVE_SEED`.
|
|
185
|
+
2. Run `baseline launch --mode standard`.
|
|
186
|
+
3. Confirm the artifact has four ordered calls.
|
|
187
|
+
4. Submit the batch with `send_calls`.
|
|
188
|
+
5. Wait for approval, poll status, then run `baseline info`.
|
|
189
|
+
|
|
190
|
+
Launch on Base mainnet:
|
|
191
|
+
|
|
192
|
+
1. Confirm the user explicitly requested Base mainnet production execution.
|
|
193
|
+
2. Use chain ID `8453` and reserve
|
|
194
|
+
`0x4200000000000000000000000000000000000006`.
|
|
195
|
+
3. Validate the artifact carefully before `send_calls`.
|
|
196
|
+
4. Submit with `chain: "base"` only after the user confirms the mainnet launch.
|
|
197
|
+
|
|
198
|
+
User asks to run from a phone or chat-only app:
|
|
199
|
+
|
|
200
|
+
1. Stop.
|
|
201
|
+
2. Explain that this plugin is CLI-only and requires a shell-capable harness.
|
|
202
|
+
3. Do not use HTTP, pasted URLs, private keys, or hand-built calldata as a
|
|
203
|
+
workaround.
|
|
204
|
+
|
|
205
|
+
## Risks & Warnings
|
|
206
|
+
|
|
207
|
+
- `irreversible`: A submitted launch cannot be undone through this plugin.
|
|
208
|
+
Confirm chain, token name, symbol, supply, reserve, fees, creator, and fee
|
|
209
|
+
recipient before `send_calls`.
|
|
210
|
+
- `local-exec`: The plugin runs the Baseline CLI on the user's machine. Use the
|
|
211
|
+
installed `baseline` binary when trusted by the user, or the documented `npx`
|
|
212
|
+
package invocation.
|
|
213
|
+
- `low-liquidity`: New token pools may have thin liquidity and volatile prices.
|
|
214
|
+
Do not imply liquidity, execution quality, or market safety beyond the
|
|
215
|
+
explicit launch inputs.
|
|
216
|
+
|
|
217
|
+
## Notes
|
|
218
|
+
|
|
219
|
+
Constants:
|
|
220
|
+
|
|
221
|
+
```text
|
|
222
|
+
base.chain: base
|
|
223
|
+
base.chainId: 8453
|
|
224
|
+
base.reserve: 0x4200000000000000000000000000000000000006
|
|
225
|
+
baseSepolia.chain: base-sepolia
|
|
226
|
+
baseSepolia.chainId: 84532
|
|
227
|
+
baseSepolia.reserve: 0xB85885897D297000A74eA2e4711C3Ca729461ABC
|
|
228
|
+
relay: 0xc81Fd894C0acE037d133aF4886550aC8133568E8
|
|
229
|
+
zeroBytes32: 0x0000000000000000000000000000000000000000000000000000000000000000
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Default launch assumptions:
|
|
233
|
+
|
|
234
|
+
- `zrp` is the default launch mode.
|
|
235
|
+
- Swap fee defaults to `1%`; protocol bounds are `0.15%` to `50%`.
|
|
236
|
+
- Creator fee share defaults to `50%`.
|
|
237
|
+
- Creator defaults to the launch account.
|
|
238
|
+
- Fee recipient defaults to creator.
|
|
239
|
+
- Salt defaults to zero `bytes32`.
|
|
240
|
+
- Reserve decimals default to `18`.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: launch
|
|
3
|
+
description: Builds Baseline token launch artifacts with the Baseline CLI and optionally executes them with an explicit signer. Use when a user wants to launch a Baseline token, generate launch calls, create wallet_sendCalls JSON, or use `baseline launch`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Launch
|
|
7
|
+
|
|
8
|
+
Use this skill to guide agents through `baseline launch`. The default workflow
|
|
9
|
+
is to build and review an unsigned call artifact; execute only when the user
|
|
10
|
+
explicitly asks for live submission.
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
Show the command surface first when inputs are unclear:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
baseline launch --help
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Build a ZRP launch artifact:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
baseline launch \
|
|
24
|
+
--mode zrp \
|
|
25
|
+
--chain-id "$CHAIN_ID" \
|
|
26
|
+
--account "$ACCOUNT" \
|
|
27
|
+
--name "$TOKEN_NAME" \
|
|
28
|
+
--symbol "$TOKEN_SYMBOL" \
|
|
29
|
+
--reserve "$RESERVE" \
|
|
30
|
+
--total-supply "$TOTAL_SUPPLY" \
|
|
31
|
+
--output .context/launches/baseline-launch.json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Artifact Contract
|
|
35
|
+
|
|
36
|
+
`baseline launch` writes wallet_sendCalls-compatible JSON:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"chainId": 84532,
|
|
41
|
+
"chain": "base-sepolia",
|
|
42
|
+
"account": "0x...",
|
|
43
|
+
"bToken": "0x...",
|
|
44
|
+
"calls": [{ "to": "0x...", "data": "0x...", "value": "0x0" }]
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Before handing the artifact to any wallet or execution layer, verify:
|
|
49
|
+
|
|
50
|
+
- `chainId`, `chain`, and `account` match the intended wallet and chain.
|
|
51
|
+
- `chain` is the executor chain slug, for example `base-sepolia`.
|
|
52
|
+
- `bToken` is the predicted address, not proof of deployment.
|
|
53
|
+
- `calls` is ordered and every call has `to`, `data`, and `value`.
|
|
54
|
+
- `zrp` has three calls; `standard` has four calls.
|
|
55
|
+
- No `execution` field is present unless the user intentionally used
|
|
56
|
+
`--execute`.
|
|
57
|
+
|
|
58
|
+
After submission, inspect deployment status and links with:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
baseline info "$BTOKEN" --chain-id "$CHAIN_ID"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Launch Modes
|
|
65
|
+
|
|
66
|
+
`zrp` is the default zero-reserve launch mode. It derives pool BTokens from
|
|
67
|
+
`--total-supply`, has no reserve seed, and has no reserve approval call.
|
|
68
|
+
|
|
69
|
+
`standard` launches with reserve liquidity and requires both pool BTokens and a
|
|
70
|
+
reserve seed:
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
baseline launch \
|
|
74
|
+
--mode standard \
|
|
75
|
+
--chain-id "$CHAIN_ID" \
|
|
76
|
+
--account "$ACCOUNT" \
|
|
77
|
+
--name "$TOKEN_NAME" \
|
|
78
|
+
--symbol "$TOKEN_SYMBOL" \
|
|
79
|
+
--reserve "$RESERVE" \
|
|
80
|
+
--total-supply "$TOTAL_SUPPLY" \
|
|
81
|
+
--initial-pool-btokens "$POOL_BTOKENS" \
|
|
82
|
+
--initial-pool-reserves "$RESERVE_SEED" \
|
|
83
|
+
--output .context/launches/baseline-launch.json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Execution
|
|
87
|
+
|
|
88
|
+
Only execute when the user explicitly asks for local signer submission.
|
|
89
|
+
|
|
90
|
+
Reuse the artifact command and add `--execute --private-key "$PRIVATE_KEY"`.
|
|
91
|
+
`BASELINE_PRIVATE_KEY` may be used instead of `--private-key`. `--account` is
|
|
92
|
+
optional with `--execute` because the CLI can derive it from the private key.
|
|
93
|
+
The CLI sends sequential transactions and returns `execution.transactions`.
|
|
94
|
+
Do not use `--execute` for external executors such as Base MCP, Bankr, or Aeon;
|
|
95
|
+
those consume `artifact.calls`.
|
|
96
|
+
Never print, commit, or persist private keys.
|
|
97
|
+
|
|
98
|
+
## Defaults And Notes
|
|
99
|
+
|
|
100
|
+
- `--chain-id` must be a chain supported by the installed Baseline CLI/SDK.
|
|
101
|
+
- `--reserve` must be the intended reserve token on that chain.
|
|
102
|
+
- Require explicit user approval before preparing or executing a production
|
|
103
|
+
launch.
|
|
104
|
+
- Swap fee defaults to `1%`; creator fee share defaults to `50%`.
|
|
105
|
+
- Creator defaults to `account`; fee recipient defaults to creator.
|
|
106
|
+
- Salt is optional and must be bytes32 when provided.
|