@cloakely/sdk 0.2.6 → 0.3.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/cloak.d.ts CHANGED
@@ -91,11 +91,12 @@ export declare class Cloak {
91
91
  readonly publicClient: PublicClient;
92
92
  readonly walletClient?: Wallet | undefined;
93
93
  readonly factory?: Address | undefined;
94
- /** The first deployment's factory, so its launches still list and settle. */
95
- readonly legacyFactory?: Address | undefined;
94
+ /** Earlier deployments' factories (newest first), so their launches still list and settle. */
95
+ readonly legacyFactory?: (Address | readonly Address[]) | undefined;
96
96
  constructor(publicClient: PublicClient, walletClient?: Wallet | undefined, factory?: Address | undefined,
97
- /** The first deployment's factory, so its launches still list and settle. */
98
- legacyFactory?: Address | undefined);
97
+ /** Earlier deployments' factories (newest first), so their launches still list and settle. */
98
+ legacyFactory?: (Address | readonly Address[]) | undefined);
99
+ private get legacyFactories();
99
100
  private wallet;
100
101
  private send;
101
102
  createLaunch(p: LaunchParams): Promise<{
@@ -105,8 +106,8 @@ export declare class Cloak {
105
106
  block: bigint;
106
107
  }>;
107
108
  /**
108
- * Every launch, newest factory first. Launches from `legacyFactory` (the first deployment) are included with
109
- * `legacy: true`; they have no vesting contract.
109
+ * Every launch, newest factory first. Launches from the `legacyFactory` list (earlier deployments) are included with
110
+ * `legacy: true`; the first deployment's have no vesting contract.
110
111
  */
111
112
  listLaunches(): Promise<{
112
113
  auction: Address;
@@ -115,6 +116,7 @@ export declare class Cloak {
115
116
  launchpad: Address;
116
117
  creatorAlloc: bigint;
117
118
  vesting: Address;
119
+ factory: Address;
118
120
  legacy?: boolean;
119
121
  }[]>;
120
122
  private listLegacy;
@@ -722,6 +724,20 @@ export declare class Cloak {
722
724
  readonly internalType: "uint256";
723
725
  }];
724
726
  readonly stateMutability: "view";
727
+ }, {
728
+ readonly type: "function";
729
+ readonly name: "refundOwed";
730
+ readonly inputs: readonly [{
731
+ readonly name: "";
732
+ readonly type: "address";
733
+ readonly internalType: "address";
734
+ }];
735
+ readonly outputs: readonly [{
736
+ readonly name: "";
737
+ readonly type: "uint256";
738
+ readonly internalType: "uint256";
739
+ }];
740
+ readonly stateMutability: "view";
725
741
  }, {
726
742
  readonly type: "function";
727
743
  readonly name: "releaseLP";
@@ -859,6 +875,16 @@ export declare class Cloak {
859
875
  readonly inputs: readonly [];
860
876
  readonly outputs: readonly [];
861
877
  readonly stateMutability: "nonpayable";
878
+ }, {
879
+ readonly type: "function";
880
+ readonly name: "withdrawRefund";
881
+ readonly inputs: readonly [{
882
+ readonly name: "to";
883
+ readonly type: "address";
884
+ readonly internalType: "address";
885
+ }];
886
+ readonly outputs: readonly [];
887
+ readonly stateMutability: "nonpayable";
862
888
  }, {
863
889
  readonly type: "event";
864
890
  readonly name: "Claimed";
@@ -1039,6 +1065,41 @@ export declare class Cloak {
1039
1065
  readonly internalType: "uint256";
1040
1066
  }];
1041
1067
  readonly anonymous: false;
1068
+ }, {
1069
+ readonly type: "event";
1070
+ readonly name: "RefundHeld";
1071
+ readonly inputs: readonly [{
1072
+ readonly name: "bidder";
1073
+ readonly type: "address";
1074
+ readonly indexed: true;
1075
+ readonly internalType: "address";
1076
+ }, {
1077
+ readonly name: "amount";
1078
+ readonly type: "uint256";
1079
+ readonly indexed: false;
1080
+ readonly internalType: "uint256";
1081
+ }];
1082
+ readonly anonymous: false;
1083
+ }, {
1084
+ readonly type: "event";
1085
+ readonly name: "RefundWithdrawn";
1086
+ readonly inputs: readonly [{
1087
+ readonly name: "bidder";
1088
+ readonly type: "address";
1089
+ readonly indexed: true;
1090
+ readonly internalType: "address";
1091
+ }, {
1092
+ readonly name: "to";
1093
+ readonly type: "address";
1094
+ readonly indexed: false;
1095
+ readonly internalType: "address";
1096
+ }, {
1097
+ readonly name: "amount";
1098
+ readonly type: "uint256";
1099
+ readonly indexed: false;
1100
+ readonly internalType: "uint256";
1101
+ }];
1102
+ readonly anonymous: false;
1042
1103
  }, {
1043
1104
  readonly type: "event";
1044
1105
  readonly name: "Revealed";
package/dist/cloak.js CHANGED
@@ -62,13 +62,16 @@ export class Cloak {
62
62
  factory;
63
63
  legacyFactory;
64
64
  constructor(publicClient, walletClient, factory,
65
- /** The first deployment's factory, so its launches still list and settle. */
65
+ /** Earlier deployments' factories (newest first), so their launches still list and settle. */
66
66
  legacyFactory) {
67
67
  this.publicClient = publicClient;
68
68
  this.walletClient = walletClient;
69
69
  this.factory = factory;
70
70
  this.legacyFactory = legacyFactory;
71
71
  }
72
+ get legacyFactories() {
73
+ return this.legacyFactory === undefined ? [] : typeof this.legacyFactory === "string" ? [this.legacyFactory] : this.legacyFactory;
74
+ }
72
75
  wallet() {
73
76
  if (!this.walletClient)
74
77
  throw new Error("Cloak: a walletClient is required for this call");
@@ -111,26 +114,25 @@ export class Cloak {
111
114
  return { auction: ev.args.auction, token: ev.args.token, txHash, block: r.blockNumber };
112
115
  }
113
116
  /**
114
- * Every launch, newest factory first. Launches from `legacyFactory` (the first deployment) are included with
115
- * `legacy: true`; they have no vesting contract.
117
+ * Every launch, newest factory first. Launches from the `legacyFactory` list (earlier deployments) are included with
118
+ * `legacy: true`; the first deployment's have no vesting contract.
116
119
  */
117
120
  async listLaunches() {
118
121
  if (!this.factory)
119
122
  throw new Error("Cloak: factory address required");
120
- const legacy = this.legacyFactory ? await this.listLegacy(this.legacyFactory) : [];
123
+ const legacy = [];
124
+ for (const f of this.legacyFactories)
125
+ legacy.push(...(await this.listLegacy(f)));
121
126
  return [...(await this.listCurrent()), ...legacy];
122
127
  }
123
128
  async listLegacy(factory) {
124
129
  const n = await this.publicClient.readContract({ address: factory, abi: cloakFactoryAbi, functionName: "launchesCount" });
125
130
  const out = [];
126
131
  for (let i = 0n; i < n; i++) {
127
- const [auction, token, creator, launchpad, creatorAlloc] = await this.publicClient.readContract({
128
- address: factory,
129
- abi: LEGACY_LAUNCHES_ABI,
130
- functionName: "launches",
131
- args: [i],
132
- });
133
- out.push({ auction, token, creator, launchpad, creatorAlloc, vesting: zeroAddress, legacy: true });
132
+ // a factory from v2 on returns a vesting contract too; the first one returns five fields
133
+ const six = await this.publicClient.readContract({ address: factory, abi: cloakFactoryAbi, functionName: "launches", args: [i] }).catch(() => null);
134
+ const [auction, token, creator, launchpad, creatorAlloc] = six ?? (await this.publicClient.readContract({ address: factory, abi: LEGACY_LAUNCHES_ABI, functionName: "launches", args: [i] }));
135
+ out.push({ auction, token, creator, launchpad, creatorAlloc, vesting: (six?.[5] ?? zeroAddress), factory, legacy: true });
134
136
  }
135
137
  return out;
136
138
  }
@@ -150,7 +152,7 @@ export class Cloak {
150
152
  functionName: "launches",
151
153
  args: [i],
152
154
  });
153
- out.push({ auction, token, creator, launchpad, creatorAlloc, vesting });
155
+ out.push({ auction, token, creator, launchpad, creatorAlloc, vesting, factory: this.factory });
154
156
  }
155
157
  return out;
156
158
  }
@@ -1,13 +1,28 @@
1
1
  import type { Address } from "viem";
2
+ /** An earlier deployment on the same chain: its launches still list, and `migrator` moves its private balances here. */
3
+ export interface PreviousDeployment {
4
+ version: number;
5
+ factory: Address;
6
+ router: Address;
7
+ routerBlock: bigint;
8
+ batcher?: Address;
9
+ /** Moves this deployment's private balances into the current one (`CloakPrivate.migrateFrom(…, { migrator })`). */
10
+ migrator?: Address;
11
+ }
2
12
  /** Where Cloak lives on each chain, so integrators never copy addresses by hand. */
3
13
  export interface CloakDeployment {
4
14
  chainId: number;
15
+ /** Which Cloak deployment this is (3 on Elysium testnet). */
16
+ version: number;
5
17
  config: Address;
6
18
  factory: Address;
19
+ /** Block the factory was deployed in: scan launch events from here. */
20
+ factoryBlock: bigint;
7
21
  router: Address;
8
22
  /** Block the router was deployed in: scan private-pool events from here. */
9
23
  routerBlock: bigint;
10
24
  batcher: Address;
25
+ /** The migrator from the newest earlier deployment (each one in `previous` has its own). */
11
26
  migrator?: Address;
12
27
  hypePool: Address;
13
28
  whype: Address;
@@ -23,12 +38,8 @@ export interface CloakDeployment {
23
38
  decimals: number;
24
39
  fromBlock: bigint;
25
40
  }[];
26
- /** The first deployment: its launches still list, and its private balances move here through `migrator`. */
27
- legacy?: {
28
- factory: Address;
29
- router: Address;
30
- routerBlock: bigint;
31
- };
41
+ /** Earlier deployments, newest first. */
42
+ previous?: PreviousDeployment[];
32
43
  }
33
44
  export declare const deployments: Record<number, CloakDeployment>;
34
45
  /** The Cloak deployment on `chainId`, or an error naming the chains Cloak is on. */
@@ -1,13 +1,16 @@
1
1
  export const deployments = {
2
+ // Cloak v3 (Oct 30): deployments/elysium-testnet-v3.json
2
3
  99801: {
3
4
  chainId: 99801,
5
+ version: 3,
4
6
  config: "0x9d30c7b23fa2d5c40779d3db3bb4292e18c94373",
5
- factory: "0xc1fc14e84cbbd10f75dad9d91bf50f47c48757fc",
6
- router: "0xd51e731467c49991496329c2b7979cb1aa220ee2",
7
- routerBlock: 15856031n,
8
- batcher: "0xa13ffd763a8cccfea1b868c616291723579ddb77",
9
- migrator: "0xe54c02fa685f2c95e5ae98e1155547194d04d9ad",
10
- hypePool: "0x4deFEC0814d11c581e5947020ac4ec41e88B55Df",
7
+ factory: "0xd0f4aacf339f07211a9155194925b2f94e250e29",
8
+ factoryBlock: 19096456n,
9
+ router: "0x78319bee7c21ca411166acc67c750aca10280e86",
10
+ routerBlock: 19096485n,
11
+ batcher: "0x9902d86c5be81f6c6ce059acf4c89193d06069c4",
12
+ migrator: "0x295f816aa6dac1901bd793120248d8f9cbbd5eec",
13
+ hypePool: "0x786886a61Dd77581ef03787c5939fC44B004064d",
11
14
  whype: "0xe44b27113D4b947c0B1bDf4a93878D0e115f4bdD",
12
15
  relayerUrl: "https://cloak-keeper.onrender.com",
13
16
  circuitsUrl: "https://cloak.boblabs.tech/circuits",
@@ -15,11 +18,24 @@ export const deployments = {
15
18
  // Elysium testnet USDC (bridged from Circle's USDC on HyperEVM): private sends and withdrawals
16
19
  { symbol: "USDC", token: "0x7D29d8047B905000459c0E80c34a26CeedcB47b2", pool: "0x61de30970e3c53665ce5a89323284e7ab379fa08", decimals: 6, fromBlock: 18329466n },
17
20
  ],
18
- legacy: {
19
- factory: "0x1dc1ea9837ecbd31ec74f0d558e1db1c303a7e1c",
20
- router: "0xfa2574cfc3afb8f7d3a0651fa2111ff4e3d2fc41",
21
- routerBlock: 10973723n,
22
- },
21
+ previous: [
22
+ {
23
+ version: 2,
24
+ factory: "0xc1fc14e84cbbd10f75dad9d91bf50f47c48757fc",
25
+ router: "0xd51e731467c49991496329c2b7979cb1aa220ee2",
26
+ routerBlock: 15856031n,
27
+ batcher: "0xa13ffd763a8cccfea1b868c616291723579ddb77",
28
+ migrator: "0x295f816aa6dac1901bd793120248d8f9cbbd5eec",
29
+ },
30
+ {
31
+ version: 1,
32
+ factory: "0x1dc1ea9837ecbd31ec74f0d558e1db1c303a7e1c",
33
+ router: "0xfa2574cfc3afb8f7d3a0651fa2111ff4e3d2fc41",
34
+ routerBlock: 10973723n,
35
+ batcher: "0xf6582cc5a84fccf74e571e652fb7b603a2c25812",
36
+ migrator: "0x5f3d82a6aa1b20ba9d0f58a98d1c4933c115a0da",
37
+ },
38
+ ],
23
39
  },
24
40
  };
25
41
  /** The Cloak deployment on `chainId`, or an error naming the chains Cloak is on. */
@@ -11,6 +11,8 @@ export interface RelayCall {
11
11
  pool: Address;
12
12
  proof: ProofArgs;
13
13
  extData: ExtData;
14
+ /** For `migrate`: the migrator from the pool's deployment into this one (the proof pays out to it). */
15
+ migrator?: Address;
14
16
  }
15
17
  /** What a relayer charges for one call, paid out of the pool's own token inside the proof. */
16
18
  export interface RelayQuote {
@@ -173,9 +175,12 @@ export declare class CloakPrivate {
173
175
  /**
174
176
  * Move every private balance `legacy` (a client on the earlier router, with the earlier keys) can see into this
175
177
  * deployment, note by note, through `CloakMigrator`. Each move is one relayed transaction: the old proof withdraws to
176
- * the migrator, which deposits the same amount here as a new note for one of this account's one-time keys.
178
+ * the migrator, which deposits the same amount here as a new note for one of this account's one-time keys. Each
179
+ * earlier deployment has its own migrator into this one: pass it as `opts.migrator` (default: `this.migrator`).
177
180
  */
178
- migrateFrom(legacy: CloakPrivate, onStatus?: Status): Promise<{
181
+ migrateFrom(legacy: CloakPrivate, onStatus?: Status, opts?: {
182
+ migrator?: Address;
183
+ }): Promise<{
179
184
  token: Address;
180
185
  amount: bigint;
181
186
  txHash: Hex;
@@ -36,10 +36,11 @@ export function relayerSubmitter(url) {
36
36
  export function walletSubmitter(publicClient, wallet, router, batcher, migrator) {
37
37
  return async (call) => {
38
38
  // viem cannot infer the nested tuple types through the union; the shapes match the ABI exactly.
39
- if (call.kind === "migrate" && !migrator)
39
+ const mig = call.migrator ?? migrator;
40
+ if (call.kind === "migrate" && !mig)
40
41
  throw new Error("no migrator configured");
41
42
  const req = call.kind === "migrate"
42
- ? { address: migrator, abi: cloakMigratorAbi, functionName: "migrate", args: [call.pool, call.proof, call.extData] }
43
+ ? { address: mig, abi: cloakMigratorAbi, functionName: "migrate", args: [call.pool, call.proof, call.extData] }
43
44
  : call.kind === "placeOrder"
44
45
  ? { address: batcher, abi: privateBatcherAbi, functionName: "placeOrder", args: [call.pool, call.proof, call.extData] }
45
46
  : call.kind === "privateSwap"
@@ -50,9 +51,11 @@ export function walletSubmitter(publicClient, wallet, router, batcher, migrator)
50
51
  if (call.kind === "placeOrder" && !batcher)
51
52
  throw new Error("no batcher configured");
52
53
  // Pad the estimate: state can change between estimation and inclusion (e.g. an order landing in a new batch round
53
- // writes fresh storage, ~60k more gas). Unused gas is refunded.
54
+ // writes fresh storage, ~60k more gas). Unused gas is refunded. Estimate from the address, not the local account:
55
+ // with a local account viem estimates twice, the second time capped at the first result, so a round turning over
56
+ // in between made that second estimate run out of gas.
54
57
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
- const est = await publicClient.estimateContractGas({ ...req, account: wallet.account });
58
+ const est = await publicClient.estimateContractGas({ ...req, account: wallet.account.address });
56
59
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
60
  const hash = await wallet.writeContract({ ...req, gas: (est * 13n) / 10n + 100000n });
58
61
  const r = await publicClient.waitForTransactionReceipt({ hash });
@@ -562,9 +565,11 @@ export class CloakPrivate {
562
565
  /**
563
566
  * Move every private balance `legacy` (a client on the earlier router, with the earlier keys) can see into this
564
567
  * deployment, note by note, through `CloakMigrator`. Each move is one relayed transaction: the old proof withdraws to
565
- * the migrator, which deposits the same amount here as a new note for one of this account's one-time keys.
568
+ * the migrator, which deposits the same amount here as a new note for one of this account's one-time keys. Each
569
+ * earlier deployment has its own migrator into this one: pass it as `opts.migrator` (default: `this.migrator`).
566
570
  */
567
- async migrateFrom(legacy, onStatus = () => { }) {
571
+ async migrateFrom(legacy, onStatus = () => { }, opts = {}) {
572
+ const migrator = opts.migrator ?? this.migratorAddress();
568
573
  const moved = [];
569
574
  const markets = await legacy.loadMarkets();
570
575
  await this.loadMarkets();
@@ -577,7 +582,7 @@ export class CloakPrivate {
577
582
  break;
578
583
  const inputs = live.slice(0, 2);
579
584
  const total = inputs.reduce((a, x) => a + x.amount, 0n);
580
- const q = await legacy.relayFee("migrate", m.pool);
585
+ const q = await this.relayFee("migrate", m.pool); // quoted by the relayer that will submit it
581
586
  if (total <= q.fee)
582
587
  break; // dust that costs more to move than it's worth
583
588
  const amount = total - q.fee;
@@ -595,13 +600,13 @@ export class CloakPrivate {
595
600
  extAmount: -amount,
596
601
  fee: q.fee,
597
602
  relayer: q.relayer,
598
- recipient: this.migratorAddress(),
603
+ recipient: migrator,
599
604
  data,
600
605
  ...(await legacy.dummy()),
601
606
  prover: await this.prover(),
602
607
  });
603
608
  onStatus(`Moving ${m.symbol ?? "balance"}: relaying…`);
604
- const txHash = await this.submit({ kind: "migrate", pool: m.pool, proof, extData });
609
+ const txHash = await this.submit({ kind: "migrate", pool: m.pool, proof, extData, migrator });
605
610
  await this.publicClient.waitForTransactionReceipt({ hash: txHash });
606
611
  moved.push({ token: m.token, amount, txHash });
607
612
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloakely/sdk",
3
- "version": "0.2.6",
3
+ "version": "0.3.1",
4
4
  "description": "Cloak on Elysium: sealed-bid token launches and private trading (shielded balances, private swaps, batch auctions, private sends) with on-device zero-knowledge proofs.",
5
5
  "keywords": [
6
6
  "cloak",