@cloakely/sdk 0.5.0 → 0.7.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 +30 -8
- package/dist/abis.d.ts +1565 -0
- package/dist/abis.js +2023 -0
- package/dist/bytecode.d.ts +9 -4
- package/dist/bytecode.js +1 -1
- package/dist/cloak.d.ts +82 -2
- package/dist/cloak.js +42 -4
- package/dist/deployments.d.ts +10 -0
- package/dist/deployments.js +14 -4
- package/dist/private/client.d.ts +55 -3
- package/dist/private/client.js +132 -2
- package/dist/private/crypto.d.ts +8 -0
- package/dist/private/crypto.js +9 -1
- package/dist/private/index.d.ts +1 -0
- package/dist/private/index.js +1 -0
- package/dist/private/prover.d.ts +19 -0
- package/dist/private/prover.js +48 -0
- package/dist/private/shared.d.ts +127 -0
- package/dist/private/shared.js +459 -0
- package/dist/private/tx.d.ts +5 -0
- package/dist/private/tx.js +8 -2
- package/dist/registry.d.ts +5 -0
- package/dist/registry.js +3 -0
- package/package.json +1 -1
package/dist/cloak.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type Account, type Address, type Chain, type Hex, type PublicClient, type Transport, type WalletClient } from "viem";
|
|
2
|
+
/** `lpLockUntil` for "locked forever, the creator earns the pool's trading fees". */
|
|
3
|
+
export declare const LOCK_FOREVER_FEES: bigint;
|
|
2
4
|
import { type BidPreimage } from "./seal.js";
|
|
3
5
|
export type Wallet = WalletClient<Transport, Chain, Account>;
|
|
4
6
|
export interface LaunchParams {
|
|
@@ -21,8 +23,11 @@ export interface LaunchParams {
|
|
|
21
23
|
revealEnd: number;
|
|
22
24
|
/** Share of the raise that seeds the pool, in bps (default 5000). */
|
|
23
25
|
lpBps?: number;
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
+
/**
|
|
27
|
+
* What happens to the pool's LP: "burn" (default) burns it; "fees" locks it forever and pays the creator the pool's
|
|
28
|
+
* 0.3% trading fees (CloakFeeLocker); a unix time locks it until then, when the creator can take it.
|
|
29
|
+
*/
|
|
30
|
+
lpLockUntil?: number | "burn" | "fees";
|
|
26
31
|
noRevealPenaltyBps?: number;
|
|
27
32
|
creator?: Address;
|
|
28
33
|
metadataURI?: string;
|
|
@@ -57,6 +62,8 @@ export interface AuctionState {
|
|
|
57
62
|
pair: Address;
|
|
58
63
|
/** The launch's Uniswap V2 pool (token / WHYPE), tradable and tracked everywhere. Zero for a CloakPair market. */
|
|
59
64
|
uniPair: Address;
|
|
65
|
+
/** The LP is locked forever and the creator earns its trading fees (see `creatorFees`). */
|
|
66
|
+
creatorFees: boolean;
|
|
60
67
|
tokenName: string;
|
|
61
68
|
tokenSymbol: string;
|
|
62
69
|
/** Launch fee on a successful raise, fixed when the auction was created. */
|
|
@@ -126,6 +133,20 @@ export declare class Cloak {
|
|
|
126
133
|
private listLegacy;
|
|
127
134
|
private listCurrent;
|
|
128
135
|
getAuction(auction: Address): Promise<AuctionState>;
|
|
136
|
+
/**
|
|
137
|
+
* The creator's trading fees for a launch whose LP is locked forever: what can be claimed now (in tokens and WHYPE),
|
|
138
|
+
* who receives it, and the locker position. `null` for launches without creator fees.
|
|
139
|
+
*/
|
|
140
|
+
creatorFees(auction: Address): Promise<{
|
|
141
|
+
locker: Address;
|
|
142
|
+
position: bigint;
|
|
143
|
+
beneficiary: Address;
|
|
144
|
+
claimableLp: bigint;
|
|
145
|
+
tokens: bigint;
|
|
146
|
+
whype: bigint;
|
|
147
|
+
} | null>;
|
|
148
|
+
/** Pay a launch's earned trading fees to its creator (anyone can send this; the fees always go to the creator). */
|
|
149
|
+
claimCreatorFees(auction: Address): Promise<Hex>;
|
|
129
150
|
/** Revealed demand per tick (empty until the reveal phase — that is the point). */
|
|
130
151
|
demandCurve(auction: Address): Promise<{
|
|
131
152
|
tick: number;
|
|
@@ -225,6 +246,10 @@ export declare class Cloak {
|
|
|
225
246
|
readonly name: "seeder_";
|
|
226
247
|
readonly type: "address";
|
|
227
248
|
readonly internalType: "contract IMarketSeeder";
|
|
249
|
+
}, {
|
|
250
|
+
readonly name: "feeLocker_";
|
|
251
|
+
readonly type: "address";
|
|
252
|
+
readonly internalType: "contract IFeeLocker";
|
|
228
253
|
}];
|
|
229
254
|
readonly stateMutability: "nonpayable";
|
|
230
255
|
}, {
|
|
@@ -260,6 +285,16 @@ export declare class Cloak {
|
|
|
260
285
|
readonly internalType: "uint256";
|
|
261
286
|
}];
|
|
262
287
|
readonly stateMutability: "view";
|
|
288
|
+
}, {
|
|
289
|
+
readonly type: "function";
|
|
290
|
+
readonly name: "LOCK_FOREVER_FEES";
|
|
291
|
+
readonly inputs: readonly [];
|
|
292
|
+
readonly outputs: readonly [{
|
|
293
|
+
readonly name: "";
|
|
294
|
+
readonly type: "uint64";
|
|
295
|
+
readonly internalType: "uint64";
|
|
296
|
+
}];
|
|
297
|
+
readonly stateMutability: "view";
|
|
263
298
|
}, {
|
|
264
299
|
readonly type: "function";
|
|
265
300
|
readonly name: "MAX_TICKS";
|
|
@@ -482,6 +517,16 @@ export declare class Cloak {
|
|
|
482
517
|
readonly internalType: "uint256";
|
|
483
518
|
}];
|
|
484
519
|
readonly stateMutability: "view";
|
|
520
|
+
}, {
|
|
521
|
+
readonly type: "function";
|
|
522
|
+
readonly name: "creatorFees";
|
|
523
|
+
readonly inputs: readonly [];
|
|
524
|
+
readonly outputs: readonly [{
|
|
525
|
+
readonly name: "";
|
|
526
|
+
readonly type: "bool";
|
|
527
|
+
readonly internalType: "bool";
|
|
528
|
+
}];
|
|
529
|
+
readonly stateMutability: "view";
|
|
485
530
|
}, {
|
|
486
531
|
readonly type: "function";
|
|
487
532
|
readonly name: "creatorOwed";
|
|
@@ -546,6 +591,26 @@ export declare class Cloak {
|
|
|
546
591
|
readonly internalType: "bool";
|
|
547
592
|
}];
|
|
548
593
|
readonly stateMutability: "view";
|
|
594
|
+
}, {
|
|
595
|
+
readonly type: "function";
|
|
596
|
+
readonly name: "feeLocker";
|
|
597
|
+
readonly inputs: readonly [];
|
|
598
|
+
readonly outputs: readonly [{
|
|
599
|
+
readonly name: "";
|
|
600
|
+
readonly type: "address";
|
|
601
|
+
readonly internalType: "contract IFeeLocker";
|
|
602
|
+
}];
|
|
603
|
+
readonly stateMutability: "view";
|
|
604
|
+
}, {
|
|
605
|
+
readonly type: "function";
|
|
606
|
+
readonly name: "feePosition";
|
|
607
|
+
readonly inputs: readonly [];
|
|
608
|
+
readonly outputs: readonly [{
|
|
609
|
+
readonly name: "";
|
|
610
|
+
readonly type: "uint256";
|
|
611
|
+
readonly internalType: "uint256";
|
|
612
|
+
}];
|
|
613
|
+
readonly stateMutability: "view";
|
|
549
614
|
}, {
|
|
550
615
|
readonly type: "function";
|
|
551
616
|
readonly name: "feesOwed";
|
|
@@ -1008,6 +1073,21 @@ export declare class Cloak {
|
|
|
1008
1073
|
readonly internalType: "bytes";
|
|
1009
1074
|
}];
|
|
1010
1075
|
readonly anonymous: false;
|
|
1076
|
+
}, {
|
|
1077
|
+
readonly type: "event";
|
|
1078
|
+
readonly name: "CreatorFeesOn";
|
|
1079
|
+
readonly inputs: readonly [{
|
|
1080
|
+
readonly name: "locker";
|
|
1081
|
+
readonly type: "address";
|
|
1082
|
+
readonly indexed: false;
|
|
1083
|
+
readonly internalType: "address";
|
|
1084
|
+
}, {
|
|
1085
|
+
readonly name: "position";
|
|
1086
|
+
readonly type: "uint256";
|
|
1087
|
+
readonly indexed: false;
|
|
1088
|
+
readonly internalType: "uint256";
|
|
1089
|
+
}];
|
|
1090
|
+
readonly anonymous: false;
|
|
1011
1091
|
}, {
|
|
1012
1092
|
readonly type: "event";
|
|
1013
1093
|
readonly name: "DustSwept";
|
package/dist/cloak.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { zeroAddress, encodeAbiParameters, keccak256, parseEventLogs, toHex, } from "viem";
|
|
2
|
-
import { cloakAuctionAbi, cloakFactoryAbi, cloakPairAbi, cloakTokenAbi } from "./abis.js";
|
|
2
|
+
import { cloakAuctionAbi, cloakFactoryAbi, cloakFeeLockerAbi, cloakPairAbi, cloakTokenAbi } from "./abis.js";
|
|
3
|
+
/** `lpLockUntil` for "locked forever, the creator earns the pool's trading fees". */
|
|
4
|
+
export const LOCK_FOREVER_FEES = 2n ** 64n - 1n;
|
|
3
5
|
import { drandRoundAt, sealBid, unsealBid } from "./seal.js";
|
|
4
6
|
const WAD = 10n ** 18n;
|
|
5
7
|
const PHASES = ["commit", "reveal", "settle", "settled"];
|
|
@@ -88,7 +90,7 @@ export class Cloak {
|
|
|
88
90
|
if (!this.factory)
|
|
89
91
|
throw new Error("Cloak: factory address required");
|
|
90
92
|
const w = this.wallet();
|
|
91
|
-
const lock = p.lpLockUntil === undefined || p.lpLockUntil === "burn" ?
|
|
93
|
+
const lock = p.lpLockUntil === undefined || p.lpLockUntil === "burn" ? 0n : p.lpLockUntil === "fees" ? LOCK_FOREVER_FEES : BigInt(p.lpLockUntil);
|
|
92
94
|
const params = {
|
|
93
95
|
creator: p.creator ?? w.account.address,
|
|
94
96
|
saleSupply: p.saleSupply,
|
|
@@ -100,7 +102,7 @@ export class Cloak {
|
|
|
100
102
|
revealEnd: BigInt(p.revealEnd),
|
|
101
103
|
lpBps: p.lpBps ?? 5000,
|
|
102
104
|
noRevealPenaltyBps: p.noRevealPenaltyBps ?? 1000,
|
|
103
|
-
lpLockUntil:
|
|
105
|
+
lpLockUntil: lock,
|
|
104
106
|
tlockRound: BigInt(drandRoundAt(p.commitEnd)),
|
|
105
107
|
};
|
|
106
108
|
const txHash = await w.writeContract({
|
|
@@ -147,7 +149,7 @@ export class Cloak {
|
|
|
147
149
|
async getAuction(auction) {
|
|
148
150
|
const c = { address: auction, abi: cloakAuctionAbi };
|
|
149
151
|
const r = this.publicClient;
|
|
150
|
-
const [params, token, phase, commits, reveals, totalDeposits, totalDemand, settled, failed, clearingTick, clearingPrice, sold, raised, pair, launchFeeBps, bidCap, depositCap, creatorOwed, feesOwed, uniPair] = await Promise.all([
|
|
152
|
+
const [params, token, phase, commits, reveals, totalDeposits, totalDemand, settled, failed, clearingTick, clearingPrice, sold, raised, pair, launchFeeBps, bidCap, depositCap, creatorOwed, feesOwed, uniPair, creatorFees] = await Promise.all([
|
|
151
153
|
r.readContract({ ...c, functionName: "params" }),
|
|
152
154
|
r.readContract({ ...c, functionName: "token" }),
|
|
153
155
|
r.readContract({ ...c, functionName: "phase" }),
|
|
@@ -170,6 +172,7 @@ export class Cloak {
|
|
|
170
172
|
r.readContract({ ...c, functionName: "feesOwed" }).catch(() => 0n),
|
|
171
173
|
// launches from the Uniswap factory on
|
|
172
174
|
r.readContract({ ...c, functionName: "uniPair" }).catch(() => zeroAddress),
|
|
175
|
+
r.readContract({ ...c, functionName: "creatorFees" }).catch(() => false),
|
|
173
176
|
]);
|
|
174
177
|
const [creator, saleSupply, lpReserve, minPrice, tickSize, numTicks, commitEnd, revealEnd, lpBps, noRevealPenaltyBps, lpLockUntil, tlockRound] = params;
|
|
175
178
|
const [tokenName, tokenSymbol] = await Promise.all([
|
|
@@ -204,6 +207,7 @@ export class Cloak {
|
|
|
204
207
|
raised,
|
|
205
208
|
pair,
|
|
206
209
|
uniPair,
|
|
210
|
+
creatorFees,
|
|
207
211
|
tokenName,
|
|
208
212
|
tokenSymbol,
|
|
209
213
|
launchFeeBps,
|
|
@@ -213,6 +217,40 @@ export class Cloak {
|
|
|
213
217
|
feesOwed,
|
|
214
218
|
};
|
|
215
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* The creator's trading fees for a launch whose LP is locked forever: what can be claimed now (in tokens and WHYPE),
|
|
222
|
+
* who receives it, and the locker position. `null` for launches without creator fees.
|
|
223
|
+
*/
|
|
224
|
+
async creatorFees(auction) {
|
|
225
|
+
const c = { address: auction, abi: cloakAuctionAbi };
|
|
226
|
+
const on = await this.publicClient.readContract({ ...c, functionName: "creatorFees" }).catch(() => false);
|
|
227
|
+
if (!on)
|
|
228
|
+
return null;
|
|
229
|
+
const [locker, position, token, uniPair] = await Promise.all([
|
|
230
|
+
this.publicClient.readContract({ ...c, functionName: "feeLocker" }),
|
|
231
|
+
this.publicClient.readContract({ ...c, functionName: "feePosition" }),
|
|
232
|
+
this.publicClient.readContract({ ...c, functionName: "token" }),
|
|
233
|
+
this.publicClient.readContract({ ...c, functionName: "uniPair" }),
|
|
234
|
+
]);
|
|
235
|
+
const l = { address: locker, abi: cloakFeeLockerAbi };
|
|
236
|
+
const [pos, claimableLp, [a0, a1], token0] = await Promise.all([
|
|
237
|
+
this.publicClient.readContract({ ...l, functionName: "positions", args: [position] }),
|
|
238
|
+
this.publicClient.readContract({ ...l, functionName: "claimable", args: [position] }),
|
|
239
|
+
this.publicClient.readContract({ ...l, functionName: "claimableAmounts", args: [position] }),
|
|
240
|
+
this.publicClient.readContract({ address: uniPair, abi: [{ type: "function", name: "token0", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] }], functionName: "token0" }),
|
|
241
|
+
]);
|
|
242
|
+
const tokenIs0 = token0.toLowerCase() === token.toLowerCase();
|
|
243
|
+
return { locker, position, beneficiary: pos.beneficiary, claimableLp, tokens: tokenIs0 ? a0 : a1, whype: tokenIs0 ? a1 : a0 };
|
|
244
|
+
}
|
|
245
|
+
/** Pay a launch's earned trading fees to its creator (anyone can send this; the fees always go to the creator). */
|
|
246
|
+
async claimCreatorFees(auction) {
|
|
247
|
+
const f = await this.creatorFees(auction);
|
|
248
|
+
if (!f)
|
|
249
|
+
throw new Error("this launch has no creator fees");
|
|
250
|
+
if (f.claimableLp === 0n)
|
|
251
|
+
throw new Error("no fees earned yet");
|
|
252
|
+
return this.send(await this.wallet().writeContract({ address: f.locker, abi: cloakFeeLockerAbi, functionName: "claim", args: [f.position] })).then((r) => r.transactionHash);
|
|
253
|
+
}
|
|
216
254
|
/** Revealed demand per tick (empty until the reveal phase — that is the point). */
|
|
217
255
|
async demandCurve(auction) {
|
|
218
256
|
const s = await this.getAuction(auction);
|
package/dist/deployments.d.ts
CHANGED
|
@@ -32,12 +32,22 @@ export interface CloakDeployment {
|
|
|
32
32
|
earlierFactories?: Address[];
|
|
33
33
|
/** Block of this deployment's first factory: scan its launches' bids from here (defaults to `factoryBlock`). */
|
|
34
34
|
firstFactoryBlock?: bigint;
|
|
35
|
+
/** CloakSeeder: opens each settled launch's market (a Uniswap V2 pool where the chain has one). */
|
|
36
|
+
seeder?: Address;
|
|
37
|
+
/** CloakFeeLocker: holds "locked forever" LP and pays its trading fees to the creator. */
|
|
38
|
+
feeLocker?: Address;
|
|
35
39
|
router: Address;
|
|
36
40
|
/** Block the router was deployed in: scan private-pool events from here. */
|
|
37
41
|
routerBlock: bigint;
|
|
38
42
|
batcher: Address;
|
|
39
43
|
/** Moves balances from every earlier deployment into the permanent vaults. */
|
|
40
44
|
migrator?: Address;
|
|
45
|
+
/** SharedVault: one private vault for every new Uniswap launch token (testnet experiment). */
|
|
46
|
+
shared?: Address;
|
|
47
|
+
/** Block the shared vault was deployed in: scan its notes from here. */
|
|
48
|
+
sharedBlock?: bigint;
|
|
49
|
+
/** SharedRouter: private buys, sells and hidden sends for the shared vault. */
|
|
50
|
+
sharedRouter?: Address;
|
|
41
51
|
hypePool: Address;
|
|
42
52
|
whype: Address;
|
|
43
53
|
/** Hosted relayer (POST /relay, GET /quote). */
|
package/dist/deployments.js
CHANGED
|
@@ -9,11 +9,18 @@ export const deployments = {
|
|
|
9
9
|
config: "0x9fdf166f0671166148ea98cdd3ef0118d256167f",
|
|
10
10
|
vaults: "0x24bc1d369aab3a2d741a48f8cac1af5dfd9f3d43",
|
|
11
11
|
vaultsBlock: 19485039n,
|
|
12
|
-
// the
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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"],
|
|
16
17
|
firstFactoryBlock: 19484794n,
|
|
18
|
+
seeder: "0x633aa82b806dafc0ae4c84418d23f3726139a88d",
|
|
19
|
+
feeLocker: "0x3b74062a72b16f9a221d63515518a635414501d8",
|
|
20
|
+
// the shared launch-token vault (Nov 2, testnet experiment): new Uniswap launches keep their private balances here
|
|
21
|
+
shared: "0x0ce2ecb0195e07899377e3d7b01e927ab3f87610",
|
|
22
|
+
sharedBlock: 21426599n,
|
|
23
|
+
sharedRouter: "0xe2a0769a5acbd987c1b6725247c56187a112dc7e",
|
|
17
24
|
router: "0x343ab9a7aac93cee28321410510ea24417cc6386",
|
|
18
25
|
routerBlock: 19485063n,
|
|
19
26
|
batcher: "0xc69e4bca18020ae93bc9f17093985bfb139a3203",
|
|
@@ -93,6 +100,9 @@ export async function liveDeployment(publicClient, base) {
|
|
|
93
100
|
routerBlock: reg.routerBlock,
|
|
94
101
|
batcher: reg.batcher ?? base.batcher,
|
|
95
102
|
migrator: reg.migrator ?? base.migrator,
|
|
103
|
+
shared: reg.shared ?? base.shared,
|
|
104
|
+
sharedBlock: reg.sharedBlock ?? base.sharedBlock,
|
|
105
|
+
sharedRouter: reg.sharedRouter ?? base.sharedRouter,
|
|
96
106
|
hypePool,
|
|
97
107
|
whype,
|
|
98
108
|
previous: reg.previous.length
|
package/dist/private/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Address, type Hex, type PublicClient } from "viem";
|
|
2
|
-
import type
|
|
2
|
+
import { type Wallet } from "../cloak.js";
|
|
3
3
|
import { CloakKeys } from "./crypto.js";
|
|
4
4
|
import { MerkleTree } from "./tree.js";
|
|
5
5
|
import type { ProofArgs, Prover } from "./prover.js";
|
|
@@ -114,7 +114,11 @@ export declare class CloakPrivate {
|
|
|
114
114
|
relayFee(kind: RelayKind, pool: Address): Promise<RelayQuote>;
|
|
115
115
|
/** What a withdrawal of `amount` from `pool` delivers after the protocol's withdrawal fee. */
|
|
116
116
|
afterFee(pool: Address, amount: bigint): Promise<bigint>;
|
|
117
|
-
|
|
117
|
+
changeOutput(amount: bigint): Promise<{
|
|
118
|
+
amount: bigint;
|
|
119
|
+
pubKey: bigint;
|
|
120
|
+
memo: (b: bigint) => `0x${string}`;
|
|
121
|
+
}>;
|
|
118
122
|
dummy(): Promise<{
|
|
119
123
|
dummyPubKey: bigint;
|
|
120
124
|
dummyMemo: (b: bigint) => `0x${string}`;
|
|
@@ -123,7 +127,7 @@ export declare class CloakPrivate {
|
|
|
123
127
|
* Get 1–2 notes (from one tree epoch) covering `target`, merging notes privately first when the balance is spread
|
|
124
128
|
* across many. Each merge is a relayed transaction and pays the relayer's fee from the merged notes.
|
|
125
129
|
*/
|
|
126
|
-
|
|
130
|
+
inputsFor(pool: Address, target: bigint, onStatus: Status): Promise<OwnedNote[]>;
|
|
127
131
|
/** Public HYPE → private balance. This one step is public (your wallet deposits); everything after is not. */
|
|
128
132
|
shieldHype(wallet: Wallet, amount: bigint): Promise<Hex>;
|
|
129
133
|
/**
|
|
@@ -140,6 +144,54 @@ export declare class CloakPrivate {
|
|
|
140
144
|
txHash: Hex;
|
|
141
145
|
tokens: bigint;
|
|
142
146
|
}>;
|
|
147
|
+
/**
|
|
148
|
+
* One-time bid wallet `n` for `auction`. The private balance pays its deposit and a little gas through a relayed
|
|
149
|
+
* withdrawal, so on-chain the bid comes from a fresh address nobody can tie to this account's wallet.
|
|
150
|
+
*/
|
|
151
|
+
bidWallet(auction: Address, n: number): {
|
|
152
|
+
n: number;
|
|
153
|
+
address: Address;
|
|
154
|
+
wallet: Wallet;
|
|
155
|
+
};
|
|
156
|
+
/** Gas a bid wallet keeps for its own transactions: the bid, a private claim, and moving what's left back in. */
|
|
157
|
+
bidGasReserve(): Promise<bigint>;
|
|
158
|
+
/** This account's bid wallets for `auction` that have been used (newest last), found from the seed alone. */
|
|
159
|
+
bidWallets(auction: Address): Promise<{
|
|
160
|
+
n: number;
|
|
161
|
+
address: Address;
|
|
162
|
+
wallet: Wallet;
|
|
163
|
+
}[]>;
|
|
164
|
+
/**
|
|
165
|
+
* Place a sealed bid paid from the private HYPE balance: a relayed private withdrawal funds a fresh one-time wallet
|
|
166
|
+
* with the deposit plus gas, and that wallet seals the bid. Keep the returned secret like any bid's (auto-reveal makes
|
|
167
|
+
* losing it harmless). After settlement, `finishPrivateBids` claims the tokens privately and moves the refund back.
|
|
168
|
+
*/
|
|
169
|
+
bidPrivately(auction: Address, opts: {
|
|
170
|
+
maxPrice: bigint;
|
|
171
|
+
quantity: bigint;
|
|
172
|
+
deposit?: bigint;
|
|
173
|
+
}, onStatus?: Status): Promise<{
|
|
174
|
+
secret: import("../cloak.js").BidSecret;
|
|
175
|
+
bidWallet: `0x${string}`;
|
|
176
|
+
n: number;
|
|
177
|
+
fundTx: `0x${string}`;
|
|
178
|
+
}>;
|
|
179
|
+
/**
|
|
180
|
+
* After a launch settles: for every bid this account placed from its private balance, claim won tokens straight into
|
|
181
|
+
* the private vault (or, if a cap blocks that, to the bid wallet and then in), collect refunds, and move the bid
|
|
182
|
+
* wallet's HYPE back into the private balance. Before settlement it only moves back HYPE from a one-time wallet whose
|
|
183
|
+
* bid never went through. Safe to call again; it only does what's left.
|
|
184
|
+
*/
|
|
185
|
+
finishPrivateBids(auction: Address, onStatus?: Status,
|
|
186
|
+
/** The shared launch-token vault, for launches whose token lives there (claimed to the bid wallet, then moved in). */
|
|
187
|
+
shared?: {
|
|
188
|
+
isAdmitted(token: Address): Promise<boolean>;
|
|
189
|
+
shield(wallet: Wallet, token: Address, amount: bigint): Promise<Hex>;
|
|
190
|
+
}): Promise<{
|
|
191
|
+
claimed: number;
|
|
192
|
+
movedHype: bigint;
|
|
193
|
+
movedTokens: bigint;
|
|
194
|
+
}>;
|
|
143
195
|
roundInfo(): Promise<{
|
|
144
196
|
round: bigint;
|
|
145
197
|
endsAt: number;
|
package/dist/private/client.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { encodeAbiParameters, parseEventLogs, zeroAddress } from "viem";
|
|
2
|
-
import {
|
|
1
|
+
import { createWalletClient, custom, encodeAbiParameters, parseEventLogs, zeroAddress } from "viem";
|
|
2
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
3
|
+
import { cloakAuctionAbi, cloakConfigAbi, cloakMigratorAbi, cloakPairAbi, privateBatcherAbi, privateRouterAbi, shieldedPoolAbi } from "../abis.js";
|
|
4
|
+
import { Cloak } from "../cloak.js";
|
|
3
5
|
import { ACCOUNT_MESSAGE, ACCOUNT_TYPED_DATA, ROUTER_ACCOUNT_TYPED_DATA, CloakKeys, MAIN_KEY, noteCommitment, encryptFullMemo, encryptRouterMemo, formatCloakAddress, nullifierOf, parseCloakAddress, randomField, randomKeyIndex, readMemo, } from "./crypto.js";
|
|
4
6
|
import { MerkleTree } from "./tree.js";
|
|
5
7
|
import { MOVE_DATA_ABI, ORDER_DATA_ABI, SWAP_DATA_ABI, buildTransaction, selectNotes, splitStandard } from "./tx.js";
|
|
@@ -406,6 +408,134 @@ export class CloakPrivate {
|
|
|
406
408
|
throw new Error("private claim reverted");
|
|
407
409
|
return { txHash: hash, tokens };
|
|
408
410
|
}
|
|
411
|
+
// ───────────── sealed bids paid from the private balance ─────────────
|
|
412
|
+
/**
|
|
413
|
+
* One-time bid wallet `n` for `auction`. The private balance pays its deposit and a little gas through a relayed
|
|
414
|
+
* withdrawal, so on-chain the bid comes from a fresh address nobody can tie to this account's wallet.
|
|
415
|
+
*/
|
|
416
|
+
bidWallet(auction, n) {
|
|
417
|
+
const account = privateKeyToAccount(this.keys.bidWalletKey(auction, n));
|
|
418
|
+
const chain = this.publicClient.chain;
|
|
419
|
+
if (!chain)
|
|
420
|
+
throw new Error("the public client needs a chain");
|
|
421
|
+
const wallet = createWalletClient({ account, chain, transport: custom({ request: (a) => this.publicClient.request(a) }) });
|
|
422
|
+
return { n, address: account.address, wallet };
|
|
423
|
+
}
|
|
424
|
+
/** Gas a bid wallet keeps for its own transactions: the bid, a private claim, and moving what's left back in. */
|
|
425
|
+
async bidGasReserve() {
|
|
426
|
+
const gp = await this.publicClient.getGasPrice();
|
|
427
|
+
return (gp < 100000000n ? 100000000n : gp) * 6000000n;
|
|
428
|
+
}
|
|
429
|
+
/** This account's bid wallets for `auction` that have been used (newest last), found from the seed alone. */
|
|
430
|
+
async bidWallets(auction) {
|
|
431
|
+
const out = [];
|
|
432
|
+
for (let n = 0; n < 64; n++) {
|
|
433
|
+
const w = this.bidWallet(auction, n);
|
|
434
|
+
const [nonce, bal] = await Promise.all([this.publicClient.getTransactionCount({ address: w.address }), this.publicClient.getBalance({ address: w.address })]);
|
|
435
|
+
if (nonce === 0 && bal === 0n)
|
|
436
|
+
break;
|
|
437
|
+
out.push(w);
|
|
438
|
+
}
|
|
439
|
+
return out;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Place a sealed bid paid from the private HYPE balance: a relayed private withdrawal funds a fresh one-time wallet
|
|
443
|
+
* with the deposit plus gas, and that wallet seals the bid. Keep the returned secret like any bid's (auto-reveal makes
|
|
444
|
+
* losing it harmless). After settlement, `finishPrivateBids` claims the tokens privately and moves the refund back.
|
|
445
|
+
*/
|
|
446
|
+
async bidPrivately(auction, opts, onStatus = () => { }) {
|
|
447
|
+
const reader = new Cloak(this.publicClient);
|
|
448
|
+
const s = await reader.getAuction(auction);
|
|
449
|
+
if (s.phase !== "commit")
|
|
450
|
+
throw new Error("commit phase is over");
|
|
451
|
+
const q = reader.quoteBid(s, opts.maxPrice, opts.quantity);
|
|
452
|
+
const deposit = opts.deposit ?? q.deposit;
|
|
453
|
+
if (deposit < q.cost)
|
|
454
|
+
throw new Error("deposit is below the bid's cost");
|
|
455
|
+
const used = await this.bidWallets(auction);
|
|
456
|
+
const bw = this.bidWallet(auction, used.length);
|
|
457
|
+
const gas = await this.bidGasReserve();
|
|
458
|
+
// the vault keeps its withdrawal fee from what arrives, so send enough that deposit + gas land in full
|
|
459
|
+
const config = await this.publicClient.readContract({ address: this.router, abi: privateRouterAbi, functionName: "config" });
|
|
460
|
+
const feeBps = BigInt(await this.publicClient.readContract({ address: config, abi: cloakConfigAbi, functionName: "withdrawFeeBps" }));
|
|
461
|
+
const want = deposit + gas;
|
|
462
|
+
const send = (want * 10000n + (10000n - feeBps) - 1n) / (10000n - feeBps);
|
|
463
|
+
onStatus("Paying the deposit from your private balance…");
|
|
464
|
+
const fund = await this.unshieldHype(bw.address, send, onStatus);
|
|
465
|
+
const r = await this.publicClient.waitForTransactionReceipt({ hash: fund });
|
|
466
|
+
if (r.status !== "success")
|
|
467
|
+
throw new Error("funding the bid wallet reverted");
|
|
468
|
+
for (let i = 0; i < 30 && (await this.publicClient.getBalance({ address: bw.address })) < want; i++)
|
|
469
|
+
await new Promise((x) => setTimeout(x, 1000));
|
|
470
|
+
if ((await this.publicClient.getBalance({ address: bw.address })) < deposit)
|
|
471
|
+
throw new Error("the bid wallet wasn't funded; nothing was bid, and the HYPE is in the one-time wallet (finishPrivateBids moves it back)");
|
|
472
|
+
onStatus("Sealing the bid from a one-time wallet…");
|
|
473
|
+
const secret = await new Cloak(this.publicClient, bw.wallet).bid(auction, { maxPrice: opts.maxPrice, quantity: opts.quantity, deposit });
|
|
474
|
+
return { secret, bidWallet: bw.address, n: bw.n, fundTx: fund };
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* After a launch settles: for every bid this account placed from its private balance, claim won tokens straight into
|
|
478
|
+
* the private vault (or, if a cap blocks that, to the bid wallet and then in), collect refunds, and move the bid
|
|
479
|
+
* wallet's HYPE back into the private balance. Before settlement it only moves back HYPE from a one-time wallet whose
|
|
480
|
+
* bid never went through. Safe to call again; it only does what's left.
|
|
481
|
+
*/
|
|
482
|
+
async finishPrivateBids(auction, onStatus = () => { },
|
|
483
|
+
/** The shared launch-token vault, for launches whose token lives there (claimed to the bid wallet, then moved in). */
|
|
484
|
+
shared) {
|
|
485
|
+
const reader = new Cloak(this.publicClient);
|
|
486
|
+
const s = await reader.getAuction(auction);
|
|
487
|
+
let claimed = 0;
|
|
488
|
+
let movedHype = 0n;
|
|
489
|
+
let movedTokens = 0n;
|
|
490
|
+
const vaultOpen = !s.failed && this.markets.some((m) => m.token.toLowerCase() === s.token.toLowerCase());
|
|
491
|
+
const inShared = !s.failed && !vaultOpen && !!shared && (await shared.isAdmitted(s.token));
|
|
492
|
+
for (const bw of await this.bidWallets(auction)) {
|
|
493
|
+
const c = new Cloak(this.publicClient, bw.wallet);
|
|
494
|
+
const bids = await reader.bidsOf(auction, bw.address);
|
|
495
|
+
// before settlement only a wallet whose bid never went through has anything to move back
|
|
496
|
+
if (!s.settled && bids.length > 0)
|
|
497
|
+
continue;
|
|
498
|
+
for (const b of bids) {
|
|
499
|
+
if (b.claimed)
|
|
500
|
+
continue;
|
|
501
|
+
onStatus(`Claiming bid #${b.id}…`);
|
|
502
|
+
if (b.tokens > 0n && vaultOpen) {
|
|
503
|
+
try {
|
|
504
|
+
await this.claimPrivately(bw.wallet, auction, b.id);
|
|
505
|
+
claimed++;
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
catch { } // over the vault's deposit cap: claim to the bid wallet instead
|
|
509
|
+
}
|
|
510
|
+
await c.claim(auction, [b.id]);
|
|
511
|
+
claimed++;
|
|
512
|
+
}
|
|
513
|
+
const owed = await this.publicClient.readContract({ address: auction, abi: cloakAuctionAbi, functionName: "refundOwed", args: [bw.address] }).catch(() => 0n);
|
|
514
|
+
if (owed > 0n) {
|
|
515
|
+
const h = await bw.wallet.writeContract({ address: auction, abi: cloakAuctionAbi, functionName: "withdrawRefund", args: [bw.address] });
|
|
516
|
+
await this.publicClient.waitForTransactionReceipt({ hash: h });
|
|
517
|
+
}
|
|
518
|
+
if (vaultOpen || inShared) {
|
|
519
|
+
const t = await this.publicClient.readContract({ address: s.token, abi: ERC20_ABI, functionName: "balanceOf", args: [bw.address] });
|
|
520
|
+
if (t > 0n) {
|
|
521
|
+
onStatus("Moving tokens into your private balance…");
|
|
522
|
+
try {
|
|
523
|
+
await (inShared ? shared.shield(bw.wallet, s.token, t) : this.shieldToken(bw.wallet, s.token, t));
|
|
524
|
+
movedTokens += t;
|
|
525
|
+
}
|
|
526
|
+
catch { } // a cap may block it; the tokens stay in the one-time wallet, which nobody can tie to you
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
const bal = await this.publicClient.getBalance({ address: bw.address });
|
|
530
|
+
const keep = (await this.bidGasReserve()) / 3n; // gas for this last shield
|
|
531
|
+
if (bal > keep * 2n) {
|
|
532
|
+
onStatus("Moving the refund back into your private balance…");
|
|
533
|
+
await this.shieldHype(bw.wallet, bal - keep);
|
|
534
|
+
movedHype += bal - keep;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return { claimed, movedHype, movedTokens };
|
|
538
|
+
}
|
|
409
539
|
// ───────────── batch auctions (hide trade size) ─────────────
|
|
410
540
|
async roundInfo() {
|
|
411
541
|
if (!this.batcher)
|
package/dist/private/crypto.d.ts
CHANGED
|
@@ -70,11 +70,19 @@ export declare class CloakKeys {
|
|
|
70
70
|
static fromSignature(sig: Hex): CloakKeys;
|
|
71
71
|
key(index: number): Promise<SpendKey>;
|
|
72
72
|
main(): Promise<SpendKey>;
|
|
73
|
+
/**
|
|
74
|
+
* The private key of one-time bid wallet `n` for `auction`: a fresh address that bids from the private balance, so the
|
|
75
|
+
* bid can't be linked to the account's wallet. Derived from this account's seed, so the same signature always finds
|
|
76
|
+
* it again (on any device).
|
|
77
|
+
*/
|
|
78
|
+
bidWalletKey(auction: Hex, n: number): Hex;
|
|
73
79
|
}
|
|
74
80
|
export interface Note {
|
|
75
81
|
amount: bigint;
|
|
76
82
|
pubKey: bigint;
|
|
77
83
|
blinding: bigint;
|
|
84
|
+
/** Shared vault only: the token's address as a number. Notes of single-token vaults have none. */
|
|
85
|
+
asset?: bigint;
|
|
78
86
|
}
|
|
79
87
|
export declare const noteCommitment: (n: Note) => Promise<bigint>;
|
|
80
88
|
export declare function nullifierOf(n: Note, leafIndex: number, privKey: bigint): Promise<bigint>;
|
package/dist/private/crypto.js
CHANGED
|
@@ -77,8 +77,16 @@ export class CloakKeys {
|
|
|
77
77
|
main() {
|
|
78
78
|
return this.key(MAIN_KEY);
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* The private key of one-time bid wallet `n` for `auction`: a fresh address that bids from the private balance, so the
|
|
82
|
+
* bid can't be linked to the account's wallet. Derived from this account's seed, so the same signature always finds
|
|
83
|
+
* it again (on any device).
|
|
84
|
+
*/
|
|
85
|
+
bidWalletKey(auction, n) {
|
|
86
|
+
return keccak256(concat([toBytes("cloak-bidwallet-v1"), this.seed, toBytes(auction.toLowerCase()), toBytes(toHex(n, { size: 4 }))]));
|
|
87
|
+
}
|
|
80
88
|
}
|
|
81
|
-
export const noteCommitment = (n) => poseidon([n.amount, n.pubKey, n.blinding]);
|
|
89
|
+
export const noteCommitment = (n) => n.asset === undefined ? poseidon([n.amount, n.pubKey, n.blinding]) : poseidon([n.amount, n.pubKey, n.blinding, n.asset]);
|
|
82
90
|
export async function nullifierOf(n, leafIndex, privKey) {
|
|
83
91
|
const c = await noteCommitment(n);
|
|
84
92
|
const sig = await poseidon([privKey, c, BigInt(leafIndex)]);
|
package/dist/private/index.d.ts
CHANGED
package/dist/private/index.js
CHANGED
package/dist/private/prover.d.ts
CHANGED
|
@@ -7,10 +7,14 @@ export interface ProofArgs {
|
|
|
7
7
|
extDataHash: bigint;
|
|
8
8
|
inputNullifiers: [bigint, bigint];
|
|
9
9
|
outputCommitments: [bigint, bigint];
|
|
10
|
+
/** Shared-vault proofs only: the token named publicly, or 0 for a send that hides it. */
|
|
11
|
+
publicAsset?: bigint;
|
|
10
12
|
}
|
|
11
13
|
export type Prover = (input: Record<string, unknown>) => Promise<ProofArgs>;
|
|
12
14
|
/** Groth16 prover for the 2-in/2-out circuit (`transaction2x2`). Runs on the user's device. */
|
|
13
15
|
export declare function createProver(wasm: Uint8Array, zkey: Uint8Array): Prover;
|
|
16
|
+
/** Groth16 prover for the shared launch-token vault (`transactionMA2x2`, 8 public signals). */
|
|
17
|
+
export declare function createSharedProver(wasm: Uint8Array, zkey: Uint8Array): Prover;
|
|
14
18
|
/** Hosted circuit artifacts. */
|
|
15
19
|
export declare const CIRCUITS_URL = "https://cloak.boblabs.tech/circuits";
|
|
16
20
|
/** SHA-256 of the artifacts this SDK version was built and tested against. */
|
|
@@ -29,3 +33,18 @@ export declare function loadProver(baseUrl?: string, opts?: {
|
|
|
29
33
|
zkey: string;
|
|
30
34
|
} | null;
|
|
31
35
|
}): Promise<Prover>;
|
|
36
|
+
/** SHA-256 of the shared-vault circuit artifacts this SDK version was built and tested against. */
|
|
37
|
+
export declare const SHARED_CIRCUIT_HASHES: {
|
|
38
|
+
readonly wasm: "55712f66e67fd9345daac5c881c2e73c546864dbd1e23481463b603b47aa53ed";
|
|
39
|
+
readonly zkey: "86ecee336f022ac1d2dbcc4db7e85ef838aee34c4d75fe8bc7446db86f3b97b3";
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Fetch the shared launch-token vault's circuit (`transactionMA2x2`, 15 MB, once) and build its prover. Checked against
|
|
43
|
+
* `SHARED_CIRCUIT_HASHES` like `loadProver`; pass `hashes: null` to skip that when serving your own build.
|
|
44
|
+
*/
|
|
45
|
+
export declare function loadSharedProver(baseUrl?: string, opts?: {
|
|
46
|
+
hashes?: {
|
|
47
|
+
wasm: string;
|
|
48
|
+
zkey: string;
|
|
49
|
+
} | null;
|
|
50
|
+
}): Promise<Prover>;
|