@cloakely/sdk 0.8.2 → 0.8.3

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/cloak.d.ts CHANGED
@@ -60,8 +60,12 @@ export interface AuctionState {
60
60
  raised: bigint;
61
61
  /** The market Cloak trades: a CloakV2Market in front of a Uniswap V2 pool, or (earlier launches) a CloakPair. */
62
62
  pair: Address;
63
- /** The launch's Uniswap V2 pool (token / WHYPE), tradable and tracked everywhere. Zero for a CloakPair market. */
63
+ /** The launch's Uniswap pool: a V2 pool (token / WHYPE), or for a v4 launch its CloakV4Market. Zero for a CloakPair. */
64
64
  uniPair: Address;
65
+ /** Which market the launch opens: a Uniswap v4 pool with Cloak's hook, a Uniswap V2 pool, or (earlier launches) a CloakPair. */
66
+ pool: "v4" | "v2" | "cloak";
67
+ /** For a v4 launch: the hook that seeds and looks after its pool. */
68
+ hook?: Address;
65
69
  /** The LP is locked forever and the creator earns its trading fees (see `creatorFees`). */
66
70
  creatorFees: boolean;
67
71
  tokenName: string;
@@ -115,6 +119,8 @@ export declare class Cloak {
115
119
  txHash: Hex;
116
120
  block: bigint;
117
121
  }>;
122
+ /** Whether this factory's launches may lock LP until a date (false for Uniswap v4 launches). */
123
+ timedLocks(): Promise<boolean>;
118
124
  /**
119
125
  * Every launch, newest factory first. Launches from the `legacyFactory` list (earlier deployments) are included with
120
126
  * `legacy: true`; the first deployment's have no vesting contract.
package/dist/cloak.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { zeroAddress, encodeAbiParameters, keccak256, parseEventLogs, toHex, } from "viem";
2
- import { cloakAuctionAbi, cloakFactoryAbi, cloakFeeLockerAbi, cloakPairAbi, cloakTokenAbi } from "./abis.js";
2
+ import { cloakAuctionAbi, cloakFactoryAbi, cloakFeeLockerAbi, cloakPairAbi, cloakTokenAbi, cloakV4HookAbi } from "./abis.js";
3
3
  /** `lpLockUntil` for "locked forever, the creator earns the pool's trading fees". */
4
4
  export const LOCK_FOREVER_FEES = 2n ** 64n - 1n;
5
5
  import { drandRoundAt, sealBid, unsealBid } from "./seal.js";
@@ -91,6 +91,8 @@ export class Cloak {
91
91
  throw new Error("Cloak: factory address required");
92
92
  const w = this.wallet();
93
93
  const lock = p.lpLockUntil === undefined || p.lpLockUntil === "burn" ? 0n : p.lpLockUntil === "fees" ? LOCK_FOREVER_FEES : BigInt(p.lpLockUntil);
94
+ if (lock !== 0n && lock !== LOCK_FOREVER_FEES && !(await this.timedLocks()))
95
+ throw new Error("Launches from this factory open a Uniswap v4 pool, whose liquidity stays locked: choose \"burn\" or \"fees\" (locked forever, trading fees to the creator), not a lock date.");
94
96
  const params = {
95
97
  creator: p.creator ?? w.account.address,
96
98
  saleSupply: p.saleSupply,
@@ -115,6 +117,12 @@ export class Cloak {
115
117
  const [ev] = parseEventLogs({ abi: cloakFactoryAbi, logs: r.logs, eventName: "LaunchCreated" });
116
118
  return { auction: ev.args.auction, token: ev.args.token, txHash, block: r.blockNumber };
117
119
  }
120
+ /** Whether this factory's launches may lock LP until a date (false for Uniswap v4 launches). */
121
+ async timedLocks() {
122
+ if (!this.factory)
123
+ return true;
124
+ return this.publicClient.readContract({ address: this.factory, abi: cloakFactoryAbi, functionName: "timedLocks" }).catch(() => true);
125
+ }
118
126
  /**
119
127
  * Every launch, newest factory first. Launches from the `legacyFactory` list (earlier deployments) are included with
120
128
  * `legacy: true`; the first deployment's have no vesting contract.
@@ -174,6 +182,9 @@ export class Cloak {
174
182
  r.readContract({ ...c, functionName: "uniPair" }).catch(() => zeroAddress),
175
183
  r.readContract({ ...c, functionName: "creatorFees" }).catch(() => false),
176
184
  ]);
185
+ // a v4 launch's seeder is CloakV4Hook, the only seeder that says it can't hand LP back after a timed lock
186
+ const seeder = await r.readContract({ ...c, functionName: "seeder" }).catch(() => zeroAddress);
187
+ const v4 = seeder !== zeroAddress && (await r.readContract({ address: seeder, abi: cloakV4HookAbi, functionName: "timedLocks" }).then((t) => t === false, () => false));
177
188
  const [creator, saleSupply, lpReserve, minPrice, tickSize, numTicks, commitEnd, revealEnd, lpBps, noRevealPenaltyBps, lpLockUntil, tlockRound] = params;
178
189
  const [tokenName, tokenSymbol] = await Promise.all([
179
190
  r.readContract({ address: token, abi: cloakTokenAbi, functionName: "name" }),
@@ -207,7 +218,10 @@ export class Cloak {
207
218
  raised,
208
219
  pair,
209
220
  uniPair,
210
- creatorFees,
221
+ pool: v4 ? "v4" : uniPair !== zeroAddress ? "v2" : "cloak",
222
+ ...(v4 ? { hook: seeder } : {}),
223
+ // a v4 launch "locked forever" pays its creator through the hook rather than the V2 fee locker
224
+ creatorFees: creatorFees || (v4 && BigInt(lpLockUntil) === LOCK_FOREVER_FEES),
211
225
  tokenName,
212
226
  tokenSymbol,
213
227
  launchFeeBps,
@@ -223,6 +237,18 @@ export class Cloak {
223
237
  */
224
238
  async creatorFees(auction) {
225
239
  const c = { address: auction, abi: cloakAuctionAbi };
240
+ const s = await this.getAuction(auction);
241
+ if (s.pool === "v4") {
242
+ if (!s.creatorFees || !s.hook || s.uniPair === zeroAddress)
243
+ return null;
244
+ // what collectFees would pay right now, without sending anything
245
+ const [{ result }, launch] = await Promise.all([
246
+ this.publicClient.simulateContract({ address: s.hook, abi: cloakV4HookAbi, functionName: "collectFees", args: [s.token] }),
247
+ this.publicClient.readContract({ address: s.hook, abi: cloakV4HookAbi, functionName: "launchOf", args: [s.token] }),
248
+ ]);
249
+ const [h, t] = result;
250
+ return { locker: s.hook, position: 0n, beneficiary: launch.feeTo, claimableLp: h + t > 0n ? 1n : 0n, tokens: t, whype: h };
251
+ }
226
252
  const on = await this.publicClient.readContract({ ...c, functionName: "creatorFees" }).catch(() => false);
227
253
  if (!on)
228
254
  return null;
@@ -249,6 +275,9 @@ export class Cloak {
249
275
  throw new Error("this launch has no creator fees");
250
276
  if (f.claimableLp === 0n)
251
277
  throw new Error("no fees earned yet");
278
+ const s = await this.getAuction(auction);
279
+ if (s.pool === "v4")
280
+ return this.send(await this.wallet().writeContract({ address: f.locker, abi: cloakV4HookAbi, functionName: "collectFees", args: [s.token] })).then((r) => r.transactionHash);
252
281
  return this.send(await this.wallet().writeContract({ address: f.locker, abi: cloakFeeLockerAbi, functionName: "claim", args: [f.position] })).then((r) => r.transactionHash);
253
282
  }
254
283
  /** Revealed demand per tick (empty until the reveal phase — that is the point). */
@@ -34,6 +34,10 @@ export interface CloakDeployment {
34
34
  firstFactoryBlock?: bigint;
35
35
  /** CloakSeeder: opens each settled launch's market (a Uniswap V2 pool where the chain has one). */
36
36
  seeder?: Address;
37
+ /** Uniswap v4's PoolManager (on testnet, Cloak's deployment of Uniswap's exact build; on mainnet, Uniswap's own). */
38
+ poolManager?: Address;
39
+ /** CloakV4Hook: seeds and looks after every v4 launch's pool. */
40
+ v4Hook?: Address;
37
41
  /** CloakFeeLocker: holds "locked forever" LP and pays its trading fees to the creator. */
38
42
  feeLocker?: Address;
39
43
  router: Address;
@@ -9,13 +9,17 @@ export const deployments = {
9
9
  config: "0x9fdf166f0671166148ea98cdd3ef0118d256167f",
10
10
  vaults: "0x24bc1d369aab3a2d741a48f8cac1af5dfd9f3d43",
11
11
  vaultsBlock: 19485039n,
12
- // the creator-fee launch factory (Nov 2): every launch opens a Uniswap V2 pool at its clearing price, and its LP can
13
- // be locked forever with the trading fees going to the creator
14
- factory: "0xd179bad69715f4bd4796dd7a4103be143fba02ad",
15
- factoryBlock: 21312271n,
16
- earlierFactories: ["0xeac84944f5a8343edf49cde8ef74d71f4908a656", "0xa88df63d7d44acc66052e5cbe5ba9503bf940993"],
12
+ // the Uniswap v4 launch factory (Nov 3): every launch opens a v4 pool (native HYPE / token) at its clearing price
13
+ // through CloakV4Hook, which keeps the liquidity forever, pays trading fees to the creator and charges an anti-snipe
14
+ // fee for 5 minutes after listing. The PoolManager is Uniswap's, built byte for byte like mainnet's.
15
+ factory: "0x1b0072684e98d9e23018e2d107ed8166ef84c077",
16
+ factoryBlock: 22661576n,
17
+ // the creator-fee V2 factory (Nov 2), then v4's first two
18
+ earlierFactories: ["0xd179bad69715f4bd4796dd7a4103be143fba02ad", "0xeac84944f5a8343edf49cde8ef74d71f4908a656", "0xa88df63d7d44acc66052e5cbe5ba9503bf940993"],
17
19
  firstFactoryBlock: 19484794n,
18
- seeder: "0x633aa82b806dafc0ae4c84418d23f3726139a88d",
20
+ seeder: "0xcdc11340c5ce0b3dcbd9a5e8f7838e8a8bbaaa80",
21
+ poolManager: "0x51027076df8416e42ea8438b27a0c433d9662e68",
22
+ v4Hook: "0xcdc11340c5ce0b3dcbd9a5e8f7838e8a8bbaaa80",
19
23
  feeLocker: "0x3b74062a72b16f9a221d63515518a635414501d8",
20
24
  // the shared launch-token vault (Nov 2, testnet experiment): new Uniswap launches keep their private balances here
21
25
  shared: "0x0ce2ecb0195e07899377e3d7b01e927ab3f87610",
@@ -103,7 +103,10 @@ export declare class SharedVaultClient {
103
103
  private quote;
104
104
  /** 1–2 notes of `token` covering `target`, combining notes first (a relayed send to yourself) when needed. */
105
105
  private inputsFor;
106
- /** Expected output of a swap through `token`'s Uniswap market (0.3% fee), before slippage. */
106
+ /**
107
+ * Expected output of a swap through `token`'s market, before slippage. The market prices it at its own current fee:
108
+ * 0.3% on a Uniswap V2 pool, and on a v4 pool whatever the hook charges now (higher just after listing, then 0.3%).
109
+ */
107
110
  quoteSwap(token: Address, side: "buy" | "sell", amountIn: bigint): Promise<bigint>;
108
111
  /** Wallet tokens → a private note on a one-time key. This step is public (the wallet deposits). */
109
112
  shield(wallet: Wallet, token: Address, amount: bigint, onStatus?: Status): Promise<Hex>;
@@ -260,7 +260,10 @@ export class SharedVaultClient {
260
260
  }
261
261
  throw new Error("too many notes to combine");
262
262
  }
263
- /** Expected output of a swap through `token`'s Uniswap market (0.3% fee), before slippage. */
263
+ /**
264
+ * Expected output of a swap through `token`'s market, before slippage. The market prices it at its own current fee:
265
+ * 0.3% on a Uniswap V2 pool, and on a v4 pool whatever the hook charges now (higher just after listing, then 0.3%).
266
+ */
264
267
  async quoteSwap(token, side, amountIn) {
265
268
  const m = this.info(token).market;
266
269
  const [rH, rT] = await Promise.all([
@@ -268,8 +271,7 @@ export class SharedVaultClient {
268
271
  this.pub.readContract({ address: m, abi: cloakPairAbi, functionName: "reserveToken" }),
269
272
  ]);
270
273
  const [rIn, rOut] = side === "buy" ? [rH, rT] : [rT, rH];
271
- const a = amountIn * 997n;
272
- return (a * rOut) / (rIn * 1000n + a);
274
+ return this.pub.readContract({ address: m, abi: cloakPairAbi, functionName: "getAmountOut", args: [amountIn, rIn, rOut] });
273
275
  }
274
276
  // ───────────── public → private ─────────────
275
277
  /** Wallet tokens → a private note on a one-time key. This step is public (the wallet deposits). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloakely/sdk",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "Cloak on Elysium: sealed-bid token launches, sealed NFT drops and WL spot sales, and private trading (shielded balances, private swaps, batch auctions, private sends) with on-device zero-knowledge proofs.",
5
5
  "keywords": [
6
6
  "cloak",