clockwork-press 0.2.0 → 0.2.1

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/dist/config.js CHANGED
@@ -53,6 +53,10 @@ export function validate(c) {
53
53
  bad('buyback.vest must be burn or hold');
54
54
  if (![5, 15, 30, 60].includes(c.schedule.cadenceMin))
55
55
  bad('schedule.cadenceMin must be 5, 15, 30 or 60');
56
+ if (c.claim.floor != null && !(Number(c.claim.floor) >= 0))
57
+ bad('claim.floor must be a number of the pairing asset, 0 or more');
58
+ if (c.claim.atLeastEveryHours != null && !(Number(c.claim.atLeastEveryHours) >= 1))
59
+ bad('claim.atLeastEveryHours must be 1 or more');
56
60
  if (c.launch.kind === 'pons-v2' && !(c.launch.feeEscrow && c.launch.factory))
57
61
  bad('pons-v2 launches need launch.factory and launch.feeEscrow');
58
62
  }
package/dist/env.js CHANGED
@@ -34,7 +34,7 @@ export const cfg = {
34
34
  // a native launch is quoted in eth: the pair address is the zero address and the escrow keeps it on its native ledger.
35
35
  gme: c.pair.address, pair: c.pair.address, pairSymbol: pairNative ? 'ETH' : c.pair.symbol, pairDecimals: pairNative ? 18 : c.pair.decimals ?? 18, pairNative,
36
36
  token: c.token.address, tokenSymbol: c.token.symbol, tokenName: c.token.name, totalSupply: c.token.supply ?? 1_000_000_000,
37
- escrow: (c.launch.feeEscrow || ''), locker: (c.launch.locker || ''), claimMode: c.claim.mode,
37
+ escrow: (c.launch.feeEscrow || ''), locker: (c.launch.locker || ''), claimMode: c.claim.mode, claimFloor: Number(c.claim.floor ?? 5), claimEveryHours: Number(c.claim.atLeastEveryHours ?? 24),
38
38
  hook: (c.launch.hook || '0xE5e702641Ea86F4ae6cC3cDaeD2B886f976Be044'), vault: (c.launch.vault || '0x42df2a798f82289E177311362e8f5ccC45c1219c'),
39
39
  vestMode: c.buyback?.vest ?? 'burn', paceWord: pace,
40
40
  // ops is '' when the client has no ops wallet; the ops leg then holds (and validate() refuses opsBps > 0 without one)
package/dist/jobs/init.js CHANGED
@@ -56,7 +56,7 @@ export async function runInit() {
56
56
  split: house ? { burnBps: 5000, treasuryBps: 5000, opsBps: 0, serviceBps: 0 } : { burnBps: 4500, treasuryBps: 4500, opsBps: 0, serviceBps: 1000 },
57
57
  schedule: { cadenceMin: 15, weekends: true, napUntil: null },
58
58
  slices: { rule: { kind: 'pace', pace: 'steady' }, dip: { on: false, bandBps: 1000, multiplier: 2 }, quoteSanityBps: 1500, maxSlippageBps: 300 },
59
- burn: { method: 'burn' }, buyback: { vest: 'burn' }, claim: { mode: 'auto' },
59
+ burn: { method: 'burn' }, buyback: { vest: 'burn' }, claim: { mode: 'auto', floor: pair.symbol === 'ETH' || pair.symbol === 'WETH' ? 0.05 : 5, atLeastEveryHours: 24 },
60
60
  telegram: { mode: 'shared', cards: { claim: true, slice: true, percent: true, buys: false }, buyFloorUsd: 50 },
61
61
  site: { enabled: true, modules: ['treasury', 'burns', 'holders', 'seats', 'wallet', 'rank', 'ledger'], seatThreshold: 250000 },
62
62
  brand: { name: tName, treasuryWord: 'treasury', burnWord: 'burn', accent: '#3DFF8E' },
package/dist/press.js CHANGED
@@ -332,6 +332,7 @@ async function pressOnce(runAt, commit) {
332
332
  const mine = same(s.recipient, me);
333
333
  const minPress = parseUnits(cfg.minPressGme, cfg.pairDecimals);
334
334
  let unsweptOut = '0';
335
+ let escrowOut = '0';
335
336
  // 1. Fees reach the escrow only after a sweep: on the curve they accrue as balances on the curve, in
336
337
  // the pool as pendings on the hook. The numbers are read in every mode; only auto mode sweeps,
337
338
  // claims and releases (manual: the founder claims by hand and the machine presses what it is sent).
@@ -357,9 +358,18 @@ async function pressOnce(runAt, commit) {
357
358
  if (u.tokenSide > 0n)
358
359
  console.log(`[press] ${fmtTok(u.tokenSide)} ${cfg.tokenSymbol} of fees wait on the hook too; only the pons operator converts those`);
359
360
  const o = await tryRead('escrow', () => owed(me), { pair: 0n, token: 0n });
361
+ // a claim costs gas and posts a card, so the machine waits for the claim floor, and claims whatever waits
362
+ // at least once every `atLeastEveryHours` so small fees never sit forever
363
+ const claimFloor = parseUnits(String(cfg.claimFloor), cfg.pairDecimals);
364
+ const lastClaimTs = readLedger().presses.filter((p) => (p.kind ?? 'press') === 'press').at(-1)?.ts;
365
+ const hoursSinceClaim = lastClaimTs ? (Date.now() - new Date(lastClaimTs).getTime()) / 3_600_000 : Infinity;
366
+ const claimDue = o.pair >= minPress && (o.pair >= claimFloor || hoursSinceClaim >= cfg.claimEveryHours);
367
+ escrowOut = fmtPair(o.pair, 4);
360
368
  if (o.pair >= minPress && !auto)
361
369
  console.log(`[press] the escrow holds ${fmtPair(o.pair, 4)} ${cfg.pairSymbol} for the machine (claim mode manual: not claimed by the machine)`);
362
- else if (o.pair >= minPress) {
370
+ else if (o.pair >= minPress && !claimDue)
371
+ console.log(`[press] the escrow holds ${fmtPair(o.pair, 4)} ${cfg.pairSymbol} for the machine; claims at ${cfg.claimFloor} ${cfg.pairSymbol} or after ${cfg.claimEveryHours}h (last claim ${hoursSinceClaim === Infinity ? 'never' : hoursSinceClaim.toFixed(1) + 'h ago'})`);
372
+ else if (claimDue) {
363
373
  const got = pairNum(o.pair);
364
374
  commit();
365
375
  const tx = await claimPair();
@@ -415,7 +425,7 @@ async function pressOnce(runAt, commit) {
415
425
  }
416
426
  }
417
427
  }
418
- const watched = () => ({ ...common(), feeRecipient: watch.feeRecipient, pendingRecipient: watch.pendingRecipient, unswept: unsweptOut });
428
+ const watched = () => ({ ...common(), feeRecipient: watch.feeRecipient, pendingRecipient: watch.pendingRecipient, unswept: unsweptOut, escrowOwed: escrowOut, claimFloor: cfg.claimFloor });
419
429
  // 2. The float. Everything the wallet holds is pressed; held-back ops
420
430
  // slices from earlier presses roll in naturally. A native pair keeps its gas money.
421
431
  let floatBal = await pairBal(me);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clockwork-press",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "your fees, on a clock, with receipts. the fee machine for tokens on robinhood chain.",
@@ -17,7 +17,8 @@
17
17
  "bin",
18
18
  "README.md",
19
19
  "LICENSE",
20
- "npm-shrinkwrap.json"
20
+ "npm-shrinkwrap.json",
21
+ "skills"
21
22
  ],
22
23
  "publishConfig": {
23
24
  "access": "public"
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: clockwork
3
+ description: Set up and run a Clockwork machine for a pons v2 token on Robinhood Chain. Use when a founder asks to automate their creator fees, buy back and burn, build a treasury, or "run Clockwork" for their token. Walks the human through the machine wallet, the config, the repository, the secrets, the dry run, pointing fees at the machine, and going live. Never touches a private key.
4
+ ---
5
+
6
+ # Clockwork, with an assistant next to you
7
+
8
+ Clockwork runs a token's creator fees on a clock: claims from the pons fee escrow, splits by percentages the
9
+ founder sets once, buys the token back and burns it in slices, sends the treasury share to a wallet that only
10
+ grows, and prints every hash. It runs in the founder's own GitHub repository on a wallet the founder created.
11
+ Docs: https://gmerald.xyz/clockwork/docs/
12
+
13
+ ## Rules you follow, without exception
14
+ - **Never ask for, read, print, store, or type a private key or a bot token.** The human pastes them on
15
+ GitHub's secrets page or into a `gh secret set` prompt in their own terminal. If a key appears in the chat,
16
+ tell the human it is burned and to create a fresh wallet.
17
+ - **Never send funds and never sign.** You prepare transactions; the human signs them in their own wallet.
18
+ - **Never create wallets or accounts for the human.** Tell them what to create and where.
19
+ - The treasury wallet must not be the machine wallet. The machine wallet must be fresh, funded with a little
20
+ ETH for gas, and never a main wallet.
21
+
22
+ ## What you need from the human before you start
23
+ 1. The token address (a pons v2 launch on Robinhood Chain, chain id 4663).
24
+ 2. A fresh machine wallet address, created on their device, with about 0.02 ETH on Robinhood Chain.
25
+ 3. A treasury wallet address (a cold wallet is best).
26
+ 4. The split they want. Default: 45 burn / 45 treasury / 0 ops / 10 Clockwork. The Clockwork share is at
27
+ least 10 and is what pays for the software.
28
+ 5. The pace: gentle (a claim over a day), steady (over six hours, the default), or once (one slice).
29
+ 6. Telegram: their own bot token set as a secret (they create the bot in @BotFather), or off for now.
30
+ 7. How often to claim: `claim.floor` is how much of the pairing asset must be waiting in the escrow before the machine claims (default 5), and `claim.atLeastEveryHours` claims whatever waits at least that often (default 24). A claim costs gas and posts a card; most machines keep the defaults.
31
+
32
+ ## The steps
33
+ 1. **Write the config.** In a terminal with Node 20 or newer, in an empty folder:
34
+ `npx --yes clockwork-press@0.2.0 init <token address>`
35
+ It reads the launch from the pons factory and writes `clockwork.json`. Fill `wallets.machine`,
36
+ `wallets.treasury`, the `split`, and `slices.rule` (`{ "kind": "pace", "pace": "steady" }`). If they want
37
+ Telegram, set `telegram.mode` to `own` and `telegram.chatId` to their group id. Do not put a key or a token
38
+ in this file; it is public by design.
39
+ 2. **Create the repository.** Open https://github.com/MithrilDaniel/clockwork-template and click
40
+ "Use this template", public or private, any name. Replace its `clockwork.json` with the one from step 1.
41
+ 3. **Set the secrets.** Repository Settings, Secrets and variables, Actions, New repository secret:
42
+ `MACHINE_WALLET_KEY` (the machine wallet's private key) and, for Telegram, `TELEGRAM_BOT_TOKEN`.
43
+ Or from their terminal: `gh secret set MACHINE_WALLET_KEY -R <owner>/<repo>` (it prompts and hides the
44
+ value). You never see these values.
45
+ 4. **Dry run.** Actions tab, the "clockwork" workflow, "Run workflow", job = `dry`. Read the log with the
46
+ human. Expect: the peg line, the holders line, `launch: pool` or `curve`, where fees go, what is unswept,
47
+ the float, and `dry: would swap …`. The machine refuses to run if the key belongs to a different wallet
48
+ than `wallets.machine`; that is the guard working, not a bug.
49
+ 5. **Point the fees at the machine.** First claim what is already owed to the current recipient
50
+ (`npx --yes clockwork-press@0.2.0 claimcheck` from the folder with `clockwork.json` prints it), because a
51
+ recipient change does not move credited balances. Then the current recipient signs
52
+ `transferCreatorFeeRecipient(token, machineWallet)` on the pons factory
53
+ `0x7eD598BcEf8bd9Edd8C97A195C6d13f40801EC7e`. Prepare the calldata for them (function selector
54
+ `0x2931861b`, then the token address and the machine address each left-padded to 32 bytes) and tell them
55
+ to send it as a raw transaction from that wallet with value 0. The pons UI does not show this function;
56
+ the contract has it and it takes effect immediately.
57
+ 6. **Go live.** Set `claim.mode` to `auto` in `clockwork.json` if it is not already, commit, and let the
58
+ workflow's schedule run it on the quarter hour. Optional: a cron-job.org job that POSTs to
59
+ `https://api.github.com/repos/<owner>/<repo>/actions/workflows/press.yml/dispatches` with body
60
+ `{"ref":"main"}` and a fine-grained GitHub token scoped to that one repository, for punctual ticks.
61
+ 7. **The status page** is live at `https://gmerald.xyz/clockwork/m/?r=<owner>/<repo>` after the first tick
62
+ commits. Every number on it is read from the repository the machine writes to.
63
+
64
+ ## Reading a run
65
+ - `ran N min ago, the next tick is not due; leaving`: the double-tick guard. Nothing wrong.
66
+ - `X gme of fees unswept, and they are not ours to sweep`: fees sit on the pons hook until pons sweeps
67
+ them into the escrow. The machine claims what the escrow holds. Ask pons how often the operator sweeps.
68
+ - `fees no longer point at the machine`: the recipient changed. If the founder did it, fine. If not, they
69
+ open pons and check, and they can run `clockwork handback <address>` from a machine that is still the
70
+ recipient to move fees to a wallet of their choice.
71
+ - `the key is for 0x…, but clockwork.json names 0x…`: the wrong key was pasted. Set the secret again.
72
+ - `holding: …`: the launch is between phases (swept or rescued); the machine holds the slice.
73
+
74
+ ## Commands
75
+ `init <token>` write the config from the chain · `dry` a tick without signing · `press` the tick ·
76
+ `claimcheck` what the escrow holds and what is unswept · `doctor` RPC, wallet, gas, recipient, Telegram ·
77
+ `handback <address>` claim what is credited, then move the fee recipient · `holders` the holder count.
78
+
79
+ ## What Clockwork costs
80
+ Ten percent of every claim, sent on chain by the machine, slice by slice, to the Clockwork wallet pinned in
81
+ the package (`0x6EA62Bd07FE08C7491543d495B42F6dA7ad298D0`). No setup fee. The chain is the invoice.