@cloakely/sdk 0.7.0 → 0.7.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/abis.d.ts +654 -0
- package/dist/abis.js +841 -0
- package/dist/bytecode.d.ts +1 -0
- package/dist/bytecode.js +1 -1
- package/dist/deployments.d.ts +2 -0
- package/dist/deployments.js +2 -0
- package/dist/private/shared.d.ts +30 -3
- package/dist/private/shared.js +111 -12
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +1 -0
- package/package.json +1 -1
package/dist/deployments.d.ts
CHANGED
|
@@ -48,6 +48,8 @@ export interface CloakDeployment {
|
|
|
48
48
|
sharedBlock?: bigint;
|
|
49
49
|
/** SharedRouter: private buys, sells and hidden sends for the shared vault. */
|
|
50
50
|
sharedRouter?: Address;
|
|
51
|
+
/** SharedBatcher: batch rounds for the shared vault's tokens. */
|
|
52
|
+
sharedBatcher?: Address;
|
|
51
53
|
hypePool: Address;
|
|
52
54
|
whype: Address;
|
|
53
55
|
/** Hosted relayer (POST /relay, GET /quote). */
|
package/dist/deployments.js
CHANGED
|
@@ -21,6 +21,7 @@ export const deployments = {
|
|
|
21
21
|
shared: "0x0ce2ecb0195e07899377e3d7b01e927ab3f87610",
|
|
22
22
|
sharedBlock: 21426599n,
|
|
23
23
|
sharedRouter: "0xe2a0769a5acbd987c1b6725247c56187a112dc7e",
|
|
24
|
+
sharedBatcher: "0xdc725bdeb0fca923bf2dc65232f54463b0f80820",
|
|
24
25
|
router: "0x343ab9a7aac93cee28321410510ea24417cc6386",
|
|
25
26
|
routerBlock: 19485063n,
|
|
26
27
|
batcher: "0xc69e4bca18020ae93bc9f17093985bfb139a3203",
|
|
@@ -103,6 +104,7 @@ export async function liveDeployment(publicClient, base) {
|
|
|
103
104
|
shared: reg.shared ?? base.shared,
|
|
104
105
|
sharedBlock: reg.sharedBlock ?? base.sharedBlock,
|
|
105
106
|
sharedRouter: reg.sharedRouter ?? base.sharedRouter,
|
|
107
|
+
sharedBatcher: reg.sharedBatcher ?? base.sharedBatcher,
|
|
106
108
|
hypePool,
|
|
107
109
|
whype,
|
|
108
110
|
previous: reg.previous.length
|
package/dist/private/shared.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export declare const SHARED_SWAP_DATA_ABI: readonly [{
|
|
|
39
39
|
readonly type: "uint64";
|
|
40
40
|
}];
|
|
41
41
|
}];
|
|
42
|
-
export type SharedRelayKind = "sharedTransact" | "sharedBuy" | "sharedSell" | "sharedSend";
|
|
42
|
+
export type SharedRelayKind = "sharedTransact" | "sharedBuy" | "sharedSell" | "sharedSend" | "sharedOrderBuy" | "sharedOrderSell";
|
|
43
43
|
export interface SharedRelayCall {
|
|
44
44
|
kind: SharedRelayKind;
|
|
45
45
|
/** The shared-vault proof (or, for sharedBuy, the HYPE vault proof). */
|
|
@@ -56,7 +56,7 @@ export type SharedSubmitter = ((call: SharedRelayCall) => Promise<Hex>) & {
|
|
|
56
56
|
/** POST shared-vault calls to a Cloak relayer (`services/keeper` serves `/relay-shared` and `/quote-shared`). */
|
|
57
57
|
export declare function sharedRelayerSubmitter(url: string): SharedSubmitter;
|
|
58
58
|
/** Submit shared-vault calls from a wallet (that wallet pays gas and appears as the sender). For tests and relayers. */
|
|
59
|
-
export declare function sharedWalletSubmitter(priv: CloakPrivate, wallet: Wallet, vault: Address, router: Address): SharedSubmitter;
|
|
59
|
+
export declare function sharedWalletSubmitter(priv: CloakPrivate, wallet: Wallet, vault: Address, router: Address, batcher?: Address): SharedSubmitter;
|
|
60
60
|
export interface SharedToken {
|
|
61
61
|
token: Address;
|
|
62
62
|
market: Address;
|
|
@@ -69,12 +69,16 @@ export declare class SharedVaultClient {
|
|
|
69
69
|
readonly prover: () => Promise<Prover>;
|
|
70
70
|
readonly submit: SharedSubmitter;
|
|
71
71
|
readonly fromBlock: bigint;
|
|
72
|
+
/** SharedBatcher: batch rounds that hide trade size for these tokens. */
|
|
73
|
+
readonly batcher?: Address | undefined;
|
|
72
74
|
tokens: SharedToken[];
|
|
73
75
|
private leaves;
|
|
74
76
|
private scannedUpTo;
|
|
75
77
|
private notes;
|
|
76
78
|
private nextBlock;
|
|
77
|
-
constructor(priv: CloakPrivate, vault: Address, router: Address, prover: () => Promise<Prover>, submit: SharedSubmitter, fromBlock?: bigint
|
|
79
|
+
constructor(priv: CloakPrivate, vault: Address, router: Address, prover: () => Promise<Prover>, submit: SharedSubmitter, fromBlock?: bigint,
|
|
80
|
+
/** SharedBatcher: batch rounds that hide trade size for these tokens. */
|
|
81
|
+
batcher?: Address | undefined);
|
|
78
82
|
private get pub();
|
|
79
83
|
/** Every token admitted to the vault, with its Uniswap market. */
|
|
80
84
|
loadTokens(): Promise<SharedToken[]>;
|
|
@@ -124,4 +128,27 @@ export declare class SharedVaultClient {
|
|
|
124
128
|
send(token: Address, amount: bigint, to: string, onStatus?: Status): Promise<Hex>;
|
|
125
129
|
/** Private `token` → `to` (any address). Names the token, as any withdrawal must. */
|
|
126
130
|
unshield(token: Address, amount: bigint, to: Address, onStatus?: Status): Promise<Hex>;
|
|
131
|
+
roundInfo(): Promise<{
|
|
132
|
+
round: bigint;
|
|
133
|
+
endsAt: number;
|
|
134
|
+
roundSecs: number;
|
|
135
|
+
}>;
|
|
136
|
+
/**
|
|
137
|
+
* Batched private buy or sell of a shared-vault token: the amount is split into standard sizes (1, 2, 5 × 10ⁿ), each
|
|
138
|
+
* placed by the relayer into the current round. When the round ends, buys and sells cross at the pool's average price
|
|
139
|
+
* and only the net trades on Uniswap; outputs arrive as private notes. Nobody can tell how much any one trader moved.
|
|
140
|
+
* Any remainder that isn't a standard size stays in the private balance.
|
|
141
|
+
*/
|
|
142
|
+
batch(token: Address, side: "buy" | "sell", amount: bigint, opts?: {
|
|
143
|
+
maxOrders?: number;
|
|
144
|
+
onStatus?: Status;
|
|
145
|
+
}): Promise<{
|
|
146
|
+
orders: {
|
|
147
|
+
id: bigint;
|
|
148
|
+
size: bigint;
|
|
149
|
+
round: bigint;
|
|
150
|
+
txHash: Hex;
|
|
151
|
+
}[];
|
|
152
|
+
rest: bigint;
|
|
153
|
+
}>;
|
|
127
154
|
}
|
package/dist/private/shared.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { encodeAbiParameters, formatEther, keccak256, zeroAddress } from "viem";
|
|
2
|
-
import { cloakAuctionAbi, cloakPairAbi, sharedRouterAbi, sharedVaultAbi } from "../abis.js";
|
|
1
|
+
import { encodeAbiParameters, formatEther, keccak256, parseEventLogs, zeroAddress } from "viem";
|
|
2
|
+
import { cloakAuctionAbi, cloakPairAbi, sharedBatcherAbi, sharedRouterAbi, sharedVaultAbi } from "../abis.js";
|
|
3
3
|
import { Cloak } from "../cloak.js";
|
|
4
4
|
import { MAIN_KEY, encryptFullMemo, encryptRouterMemo, noteCommitment, nullifierOf, parseCloakAddress, randomField, randomKeyIndex, readMemo } from "./crypto.js";
|
|
5
5
|
import { MerkleTree } from "./tree.js";
|
|
6
|
-
import { buildTransaction, selectNotes } from "./tx.js";
|
|
6
|
+
import { ORDER_DATA_ABI, buildTransaction, selectNotes, splitStandard } from "./tx.js";
|
|
7
7
|
/**
|
|
8
8
|
* The shared launch-token vault (testnet experiment): one private vault for every Cloak launch token that opens on
|
|
9
9
|
* Uniswap from now on, next to the single-token vaults of HYPE and USDC.
|
|
@@ -52,15 +52,21 @@ export function sharedRelayerSubmitter(url) {
|
|
|
52
52
|
return submit;
|
|
53
53
|
}
|
|
54
54
|
/** Submit shared-vault calls from a wallet (that wallet pays gas and appears as the sender). For tests and relayers. */
|
|
55
|
-
export function sharedWalletSubmitter(priv, wallet, vault, router) {
|
|
55
|
+
export function sharedWalletSubmitter(priv, wallet, vault, router, batcher) {
|
|
56
56
|
return async (call) => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
if ((call.kind === "sharedOrderBuy" || call.kind === "sharedOrderSell") && !batcher)
|
|
58
|
+
throw new Error("no shared batcher configured");
|
|
59
|
+
const req = call.kind === "sharedOrderBuy"
|
|
60
|
+
? { address: batcher, abi: sharedBatcherAbi, functionName: "placeBuy", args: [call.proof, call.extData] }
|
|
61
|
+
: call.kind === "sharedOrderSell"
|
|
62
|
+
? { address: batcher, abi: sharedBatcherAbi, functionName: "placeSell", args: [call.proof, call.extData] }
|
|
63
|
+
: call.kind === "sharedTransact"
|
|
64
|
+
? { address: vault, abi: sharedVaultAbi, functionName: "transact", args: [call.proof, call.extData] }
|
|
65
|
+
: call.kind === "sharedBuy"
|
|
66
|
+
? { address: router, abi: sharedRouterAbi, functionName: "buy", args: [call.proof, call.extData] }
|
|
67
|
+
: call.kind === "sharedSell"
|
|
68
|
+
? { address: router, abi: sharedRouterAbi, functionName: "sell", args: [call.proof, call.extData] }
|
|
69
|
+
: { address: router, abi: sharedRouterAbi, functionName: "send", args: [call.proof, call.extData, call.feeProof, call.feeExtData] };
|
|
64
70
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
71
|
const est = await priv.publicClient.estimateContractGas({ ...req, account: wallet.account.address });
|
|
66
72
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -86,18 +92,22 @@ export class SharedVaultClient {
|
|
|
86
92
|
prover;
|
|
87
93
|
submit;
|
|
88
94
|
fromBlock;
|
|
95
|
+
batcher;
|
|
89
96
|
tokens = [];
|
|
90
97
|
leaves = [];
|
|
91
98
|
scannedUpTo = 0;
|
|
92
99
|
notes = [];
|
|
93
100
|
nextBlock;
|
|
94
|
-
constructor(priv, vault, router, prover, submit, fromBlock = 0n
|
|
101
|
+
constructor(priv, vault, router, prover, submit, fromBlock = 0n,
|
|
102
|
+
/** SharedBatcher: batch rounds that hide trade size for these tokens. */
|
|
103
|
+
batcher) {
|
|
95
104
|
this.priv = priv;
|
|
96
105
|
this.vault = vault;
|
|
97
106
|
this.router = router;
|
|
98
107
|
this.prover = prover;
|
|
99
108
|
this.submit = submit;
|
|
100
109
|
this.fromBlock = fromBlock;
|
|
110
|
+
this.batcher = batcher;
|
|
101
111
|
this.nextBlock = fromBlock;
|
|
102
112
|
}
|
|
103
113
|
get pub() {
|
|
@@ -456,4 +466,93 @@ export class SharedVaultClient {
|
|
|
456
466
|
onStatus("Relaying…");
|
|
457
467
|
return this.submit({ kind: "sharedTransact", proof, extData });
|
|
458
468
|
}
|
|
469
|
+
// ───────────── batch rounds (hide trade size) ─────────────
|
|
470
|
+
async roundInfo() {
|
|
471
|
+
if (!this.batcher)
|
|
472
|
+
throw new Error("no shared batcher configured");
|
|
473
|
+
const c = { address: this.batcher, abi: sharedBatcherAbi };
|
|
474
|
+
const [round, roundSecs] = await Promise.all([this.pub.readContract({ ...c, functionName: "currentRound" }), this.pub.readContract({ ...c, functionName: "roundSecs" })]);
|
|
475
|
+
return { round, roundSecs: Number(roundSecs), endsAt: Number((round + 1n) * roundSecs) };
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Batched private buy or sell of a shared-vault token: the amount is split into standard sizes (1, 2, 5 × 10ⁿ), each
|
|
479
|
+
* placed by the relayer into the current round. When the round ends, buys and sells cross at the pool's average price
|
|
480
|
+
* and only the net trades on Uniswap; outputs arrive as private notes. Nobody can tell how much any one trader moved.
|
|
481
|
+
* Any remainder that isn't a standard size stays in the private balance.
|
|
482
|
+
*/
|
|
483
|
+
async batch(token, side, amount, opts = {}) {
|
|
484
|
+
if (!this.batcher)
|
|
485
|
+
throw new Error("no shared batcher configured");
|
|
486
|
+
if (!this.tokens.length)
|
|
487
|
+
await this.loadTokens();
|
|
488
|
+
this.info(token);
|
|
489
|
+
const onStatus = opts.onStatus ?? (() => { });
|
|
490
|
+
const asset = asNum(token);
|
|
491
|
+
const kind = side === "buy" ? "sharedOrderBuy" : "sharedOrderSell";
|
|
492
|
+
const hypePool = this.priv.hypeMarket.pool;
|
|
493
|
+
const maxOrders = opts.maxOrders ?? 6;
|
|
494
|
+
let { sizes, rest } = splitStandard(amount, maxOrders);
|
|
495
|
+
const fee = (await this.quote(kind, token)).fee;
|
|
496
|
+
if (fee > 0n) {
|
|
497
|
+
const have = side === "buy" ? await this.priv.balance(hypePool) : await this.balance(token);
|
|
498
|
+
const reserve = (n) => (fee * BigInt(n) * 5n) / 4n + fee;
|
|
499
|
+
if (sizes.reduce((a, x) => a + x, 0n) + reserve(sizes.length) > have) {
|
|
500
|
+
// every order pays its own relayer fee: use fewer orders when that's all the balance can pay for
|
|
501
|
+
let fit = false;
|
|
502
|
+
for (let n = maxOrders; n >= 1 && !fit; n--) {
|
|
503
|
+
const budget = have - reserve(n);
|
|
504
|
+
if (budget <= 0n)
|
|
505
|
+
continue;
|
|
506
|
+
({ sizes } = splitStandard(budget < amount ? budget : amount, n));
|
|
507
|
+
fit = sizes.length > 0;
|
|
508
|
+
}
|
|
509
|
+
if (!fit)
|
|
510
|
+
throw new Error("insufficient private balance");
|
|
511
|
+
rest = amount - sizes.reduce((a, x) => a + x, 0n);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (sizes.length === 0)
|
|
515
|
+
throw new Error("amount too small for a standard-size order");
|
|
516
|
+
const placed = [];
|
|
517
|
+
for (let i = 0; i < sizes.length; i++) {
|
|
518
|
+
const size = sizes[i];
|
|
519
|
+
onStatus(`Order ${i + 1}/${sizes.length}: syncing…`);
|
|
520
|
+
const q = await this.quote(kind, token);
|
|
521
|
+
let inputs;
|
|
522
|
+
try {
|
|
523
|
+
inputs = side === "buy" ? await this.priv.inputsFor(hypePool, size + q.fee, onStatus) : await this.inputsFor(token, size + q.fee, onStatus);
|
|
524
|
+
}
|
|
525
|
+
catch (e) {
|
|
526
|
+
if (!placed.length || !/insufficient private balance/.test(String(e.message)))
|
|
527
|
+
throw e;
|
|
528
|
+
rest += sizes.slice(i).reduce((a, x) => a + x, 0n);
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
const keyIndex = randomKeyIndex();
|
|
532
|
+
const outKey = await this.priv.keys.key(keyIndex);
|
|
533
|
+
const outBlinding = randomField();
|
|
534
|
+
const data = encodeAbiParameters(ORDER_DATA_ABI, [{ token, outPubKey: outKey.pubKey, outBlinding, outMemo: encryptRouterMemo(this.priv.keys.encPub, outBlinding, keyIndex) }]);
|
|
535
|
+
const change = inputs.reduce((a, x) => a + x.amount, 0n) - size - q.fee;
|
|
536
|
+
onStatus(`Order ${i + 1}/${sizes.length}: proving on this device…`);
|
|
537
|
+
const common = {
|
|
538
|
+
inputs,
|
|
539
|
+
outputs: change > 0n ? [await this.priv.changeOutput(change)] : [],
|
|
540
|
+
extAmount: -size,
|
|
541
|
+
fee: q.fee,
|
|
542
|
+
relayer: q.relayer,
|
|
543
|
+
recipient: this.batcher,
|
|
544
|
+
data,
|
|
545
|
+
...(await this.priv.dummy()),
|
|
546
|
+
};
|
|
547
|
+
const { proof, extData } = side === "buy"
|
|
548
|
+
? await buildTransaction({ ...common, tree: await this.priv.treeFor(hypePool, inputs), prover: await this.priv.prover() })
|
|
549
|
+
: await buildTransaction({ ...common, tree: await this.tree(inputs[0].epoch ?? 0), asset, publicAsset: asset, prover: await this.prover() });
|
|
550
|
+
onStatus(`Order ${i + 1}/${sizes.length}: relaying…`);
|
|
551
|
+
const txHash = await this.submit({ kind, proof, extData });
|
|
552
|
+
const rc = await this.pub.waitForTransactionReceipt({ hash: txHash });
|
|
553
|
+
const ev = parseEventLogs({ abi: sharedBatcherAbi, logs: rc.logs, eventName: "OrderPlaced" })[0];
|
|
554
|
+
placed.push({ id: ev.args.id, size, round: ev.args.round, txHash });
|
|
555
|
+
}
|
|
556
|
+
return { orders: placed, rest };
|
|
557
|
+
}
|
|
459
558
|
}
|
package/dist/registry.d.ts
CHANGED
|
@@ -42,6 +42,8 @@ export interface CloakRegistry {
|
|
|
42
42
|
sharedBlock?: bigint;
|
|
43
43
|
/** SharedRouter: private buys, sells and hidden sends for the shared vault. */
|
|
44
44
|
sharedRouter?: Address;
|
|
45
|
+
/** SharedBatcher: batch rounds for the shared vault's tokens. */
|
|
46
|
+
sharedBatcher?: Address;
|
|
45
47
|
factory: Address;
|
|
46
48
|
factoryBlock: bigint;
|
|
47
49
|
/** Earlier factories of the current version (a factory added next to the first), newest first. */
|
package/dist/registry.js
CHANGED
|
@@ -35,6 +35,7 @@ export async function readRegistry(publicClient, config) {
|
|
|
35
35
|
shared: newest("shared")?.addr,
|
|
36
36
|
sharedBlock: newest("shared")?.startBlock,
|
|
37
37
|
sharedRouter: newest("sharedRouter")?.addr,
|
|
38
|
+
sharedBatcher: newest("sharedBatcher")?.addr,
|
|
38
39
|
factory: factory.addr,
|
|
39
40
|
factoryBlock: factory.startBlock,
|
|
40
41
|
earlierFactories: entries.filter((e) => e.kind === "factory" && e.version === factory.version && e.addr !== factory.addr).reverse().map((e) => e.addr),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloakely/sdk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.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",
|