@obelyzk/sdk 1.0.0 → 1.0.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/index.mjs +1 -1
- package/dist/obelysk/index.d.mts +96 -7
- package/dist/obelysk/index.d.ts +96 -7
- package/dist/obelysk/index.js +325 -57
- package/dist/obelysk/index.mjs +313 -55
- package/dist/privacy/index.mjs +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
package/dist/obelysk/index.d.mts
CHANGED
|
@@ -924,7 +924,14 @@ declare class VM31VaultClient {
|
|
|
924
924
|
private get contractAddress();
|
|
925
925
|
private get relayerUrl();
|
|
926
926
|
private get relayerApiKey();
|
|
927
|
+
/** Cached relayer X25519 public key (fetched on first encrypted submit) */
|
|
928
|
+
private _relayerPubkey;
|
|
927
929
|
private relayerFetch;
|
|
930
|
+
/**
|
|
931
|
+
* Submit a payload to the relayer, encrypted with ECIES.
|
|
932
|
+
* Falls back to plaintext if `encrypt: false` is passed.
|
|
933
|
+
*/
|
|
934
|
+
private relayerSubmit;
|
|
928
935
|
/** Get the current Merkle root of the VM31 commitment tree */
|
|
929
936
|
getMerkleRoot(): Promise<PackedDigest>;
|
|
930
937
|
/** Get the number of leaves in the commitment tree */
|
|
@@ -969,12 +976,24 @@ declare class VM31VaultClient {
|
|
|
969
976
|
version: number;
|
|
970
977
|
algorithm: string;
|
|
971
978
|
}>;
|
|
972
|
-
/**
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
979
|
+
/**
|
|
980
|
+
* Submit a deposit transaction to the relayer.
|
|
981
|
+
* Validates denomination (privacy gap #7) and encrypts with ECIES by default.
|
|
982
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
983
|
+
*/
|
|
984
|
+
submitDeposit(params: VaultDepositParams, encrypt?: boolean): Promise<VaultSubmitResult>;
|
|
985
|
+
/**
|
|
986
|
+
* Submit a withdrawal transaction to the relayer.
|
|
987
|
+
* Withdrawals are not denomination-restricted.
|
|
988
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
989
|
+
*/
|
|
990
|
+
submitWithdraw(params: VaultWithdrawParams, encrypt?: boolean): Promise<VaultSubmitResult>;
|
|
991
|
+
/**
|
|
992
|
+
* Submit a private transfer transaction to the relayer.
|
|
993
|
+
* Transfers are not denomination-restricted.
|
|
994
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
995
|
+
*/
|
|
996
|
+
submitTransfer(params: VaultTransferParams, encrypt?: boolean): Promise<VaultSubmitResult>;
|
|
978
997
|
/** Query batch info from the relayer */
|
|
979
998
|
queryBatch(batchId: string): Promise<VaultBatchInfo>;
|
|
980
999
|
/** Fetch Merkle path for a commitment from the relayer */
|
|
@@ -1342,4 +1361,74 @@ declare class ObelyskClient {
|
|
|
1342
1361
|
requireAccount(): Account;
|
|
1343
1362
|
}
|
|
1344
1363
|
|
|
1345
|
-
|
|
1364
|
+
/**
|
|
1365
|
+
* ECIES Encryption for VM31 Relayer
|
|
1366
|
+
*
|
|
1367
|
+
* X25519 ECDH + HKDF-SHA256 + AES-256-GCM
|
|
1368
|
+
* Compatible with the Obelysk VM31 relayer (Rust: x25519-dalek + aes-gcm + hkdf)
|
|
1369
|
+
*
|
|
1370
|
+
* Uses Web Crypto API (works in Node 20+ and all modern browsers).
|
|
1371
|
+
*/
|
|
1372
|
+
interface ECIESEnvelope {
|
|
1373
|
+
ephemeral_pubkey: string;
|
|
1374
|
+
ciphertext: string;
|
|
1375
|
+
nonce: string;
|
|
1376
|
+
version: number;
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Encrypt a JSON payload for the VM31 relayer using ECIES.
|
|
1380
|
+
*
|
|
1381
|
+
* @param payload - The SubmitRequest object to encrypt
|
|
1382
|
+
* @param relayerPubkeyHex - The relayer's X25519 public key (hex, 64 chars)
|
|
1383
|
+
* @returns ECIES envelope ready to POST to /submit
|
|
1384
|
+
*/
|
|
1385
|
+
declare function eciesEncrypt(payload: unknown, relayerPubkeyHex: string): Promise<ECIESEnvelope>;
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* VM31 Deposit Denomination Whitelists
|
|
1389
|
+
*
|
|
1390
|
+
* Privacy gap #7 mitigation: deposits must use standard denominations
|
|
1391
|
+
* to prevent exact-amount correlation attacks.
|
|
1392
|
+
*
|
|
1393
|
+
* Only deposits are restricted — withdrawals and transfers are unrestricted.
|
|
1394
|
+
*/
|
|
1395
|
+
/** wBTC denominations (8 decimals) */
|
|
1396
|
+
declare const WBTC_DENOMINATIONS: readonly bigint[];
|
|
1397
|
+
/** SAGE denominations (18 decimals) */
|
|
1398
|
+
declare const SAGE_DENOMINATIONS: readonly bigint[];
|
|
1399
|
+
/** ETH denominations (18 decimals) */
|
|
1400
|
+
declare const ETH_DENOMINATIONS: readonly bigint[];
|
|
1401
|
+
/** STRK denominations (18 decimals) */
|
|
1402
|
+
declare const STRK_DENOMINATIONS: readonly bigint[];
|
|
1403
|
+
/** USDC denominations (6 decimals) */
|
|
1404
|
+
declare const USDC_DENOMINATIONS: readonly bigint[];
|
|
1405
|
+
/** All denomination lists by VM31 asset ID */
|
|
1406
|
+
declare const VM31_DENOMINATIONS: Record<number, readonly bigint[]>;
|
|
1407
|
+
/** Denomination lists by token symbol */
|
|
1408
|
+
declare const DENOMINATION_BY_SYMBOL: Record<string, readonly bigint[]>;
|
|
1409
|
+
/**
|
|
1410
|
+
* Validate that a deposit amount is a standard denomination.
|
|
1411
|
+
* Throws if the amount is not in the whitelist.
|
|
1412
|
+
* Unknown assets pass through (forward-compatible).
|
|
1413
|
+
*
|
|
1414
|
+
* @param amount - Amount in base units (e.g., wei, satoshis)
|
|
1415
|
+
* @param assetIdOrSymbol - VM31 asset ID (0-4) or token symbol
|
|
1416
|
+
*/
|
|
1417
|
+
declare function validateDenomination(amount: bigint, assetIdOrSymbol: number | string): void;
|
|
1418
|
+
/**
|
|
1419
|
+
* Split an amount into the fewest standard denominations (greedy, largest first).
|
|
1420
|
+
* Useful for automatically batching a deposit into multiple denomination-safe transactions.
|
|
1421
|
+
*
|
|
1422
|
+
* @returns denominations array and any remainder that can't be represented
|
|
1423
|
+
*/
|
|
1424
|
+
declare function splitIntoDenominations(amount: bigint, assetIdOrSymbol: number | string): {
|
|
1425
|
+
denominations: bigint[];
|
|
1426
|
+
remainder: bigint;
|
|
1427
|
+
};
|
|
1428
|
+
/**
|
|
1429
|
+
* Get valid denominations for an asset.
|
|
1430
|
+
* Returns undefined for unknown assets.
|
|
1431
|
+
*/
|
|
1432
|
+
declare function getDenominations(assetIdOrSymbol: number | string): readonly bigint[] | undefined;
|
|
1433
|
+
|
|
1434
|
+
export { type AssetPair, type BatchStatus, type BridgeConfig, type ClaimFillParams, type ClaimParams, type CommitOrderParams, ConfidentialTransferClient, DARKPOOL_ASSET_IDS, DENOMINATION_BY_SYMBOL, DarkPoolClient, type DarkPoolDepositParams, type DarkPoolOrderData, type DepositParams, type DepositResult, type ECIESEnvelope, ECPoint, ETH_DENOMINATIONS, type EpochInfo, type FundParams, type GpuTier, MAINNET_PRIVACY_POOLS, MAINNET_TOKENS, type OTCOrder, OTCOrderbookClient, type OTCTrade, ObelyskClient, type ObelyskConfig, type ObelyskNetwork, ObelyskPrivacy, OrderSide, OrderStatus, OrderType, type OrderbookConfig, type OrderbookDepth, type OrderbookDepthLevel, type PackedDigest, type PlaceLimitOrderParams, type PlaceMarketOrderParams, type PrivacyNote, PrivacyPoolClient, PrivacyRouterClient, type PrivateAccount, ProverStakingClient, type RelayerInfo, type RevealOrderParams, SAGE_DENOMINATIONS, STRK_DENOMINATIONS, ShieldedSwapClient, type ShieldedSwapParams, type StakingConfig, type Stats24h, type StealthAnnouncement, StealthClient, type StealthMetaAddress, type StealthSendParams, type StealthSpendingProof, TOKEN_DECIMALS, type TradingPair, type TransferParams, USDC_DENOMINATIONS, type VM31AssetId, VM31BridgeClient, VM31VaultClient, VM31_ASSET_IDS, VM31_DENOMINATIONS, type VaultBatchInfo, type VaultDepositParams, type VaultMerklePath, type VaultNote, type VaultSubmitResult, type VaultTransferParams, type VaultWithdrawParams, WBTC_DENOMINATIONS, type WithdrawCTParams, type WithdrawParams, type WithdrawResult, type WorkerStake, commitmentToHash, createAEHint, createEncryptionProof, deriveNullifier, ecAdd, ecMul, eciesEncrypt, elgamalEncrypt, formatAmount, getContracts, getDenominations, getRpcUrl, mod, modInverse, parseAmount, pedersenCommit, randomScalar, splitIntoDenominations, validateDenomination };
|
package/dist/obelysk/index.d.ts
CHANGED
|
@@ -924,7 +924,14 @@ declare class VM31VaultClient {
|
|
|
924
924
|
private get contractAddress();
|
|
925
925
|
private get relayerUrl();
|
|
926
926
|
private get relayerApiKey();
|
|
927
|
+
/** Cached relayer X25519 public key (fetched on first encrypted submit) */
|
|
928
|
+
private _relayerPubkey;
|
|
927
929
|
private relayerFetch;
|
|
930
|
+
/**
|
|
931
|
+
* Submit a payload to the relayer, encrypted with ECIES.
|
|
932
|
+
* Falls back to plaintext if `encrypt: false` is passed.
|
|
933
|
+
*/
|
|
934
|
+
private relayerSubmit;
|
|
928
935
|
/** Get the current Merkle root of the VM31 commitment tree */
|
|
929
936
|
getMerkleRoot(): Promise<PackedDigest>;
|
|
930
937
|
/** Get the number of leaves in the commitment tree */
|
|
@@ -969,12 +976,24 @@ declare class VM31VaultClient {
|
|
|
969
976
|
version: number;
|
|
970
977
|
algorithm: string;
|
|
971
978
|
}>;
|
|
972
|
-
/**
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
979
|
+
/**
|
|
980
|
+
* Submit a deposit transaction to the relayer.
|
|
981
|
+
* Validates denomination (privacy gap #7) and encrypts with ECIES by default.
|
|
982
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
983
|
+
*/
|
|
984
|
+
submitDeposit(params: VaultDepositParams, encrypt?: boolean): Promise<VaultSubmitResult>;
|
|
985
|
+
/**
|
|
986
|
+
* Submit a withdrawal transaction to the relayer.
|
|
987
|
+
* Withdrawals are not denomination-restricted.
|
|
988
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
989
|
+
*/
|
|
990
|
+
submitWithdraw(params: VaultWithdrawParams, encrypt?: boolean): Promise<VaultSubmitResult>;
|
|
991
|
+
/**
|
|
992
|
+
* Submit a private transfer transaction to the relayer.
|
|
993
|
+
* Transfers are not denomination-restricted.
|
|
994
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
995
|
+
*/
|
|
996
|
+
submitTransfer(params: VaultTransferParams, encrypt?: boolean): Promise<VaultSubmitResult>;
|
|
978
997
|
/** Query batch info from the relayer */
|
|
979
998
|
queryBatch(batchId: string): Promise<VaultBatchInfo>;
|
|
980
999
|
/** Fetch Merkle path for a commitment from the relayer */
|
|
@@ -1342,4 +1361,74 @@ declare class ObelyskClient {
|
|
|
1342
1361
|
requireAccount(): Account;
|
|
1343
1362
|
}
|
|
1344
1363
|
|
|
1345
|
-
|
|
1364
|
+
/**
|
|
1365
|
+
* ECIES Encryption for VM31 Relayer
|
|
1366
|
+
*
|
|
1367
|
+
* X25519 ECDH + HKDF-SHA256 + AES-256-GCM
|
|
1368
|
+
* Compatible with the Obelysk VM31 relayer (Rust: x25519-dalek + aes-gcm + hkdf)
|
|
1369
|
+
*
|
|
1370
|
+
* Uses Web Crypto API (works in Node 20+ and all modern browsers).
|
|
1371
|
+
*/
|
|
1372
|
+
interface ECIESEnvelope {
|
|
1373
|
+
ephemeral_pubkey: string;
|
|
1374
|
+
ciphertext: string;
|
|
1375
|
+
nonce: string;
|
|
1376
|
+
version: number;
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Encrypt a JSON payload for the VM31 relayer using ECIES.
|
|
1380
|
+
*
|
|
1381
|
+
* @param payload - The SubmitRequest object to encrypt
|
|
1382
|
+
* @param relayerPubkeyHex - The relayer's X25519 public key (hex, 64 chars)
|
|
1383
|
+
* @returns ECIES envelope ready to POST to /submit
|
|
1384
|
+
*/
|
|
1385
|
+
declare function eciesEncrypt(payload: unknown, relayerPubkeyHex: string): Promise<ECIESEnvelope>;
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* VM31 Deposit Denomination Whitelists
|
|
1389
|
+
*
|
|
1390
|
+
* Privacy gap #7 mitigation: deposits must use standard denominations
|
|
1391
|
+
* to prevent exact-amount correlation attacks.
|
|
1392
|
+
*
|
|
1393
|
+
* Only deposits are restricted — withdrawals and transfers are unrestricted.
|
|
1394
|
+
*/
|
|
1395
|
+
/** wBTC denominations (8 decimals) */
|
|
1396
|
+
declare const WBTC_DENOMINATIONS: readonly bigint[];
|
|
1397
|
+
/** SAGE denominations (18 decimals) */
|
|
1398
|
+
declare const SAGE_DENOMINATIONS: readonly bigint[];
|
|
1399
|
+
/** ETH denominations (18 decimals) */
|
|
1400
|
+
declare const ETH_DENOMINATIONS: readonly bigint[];
|
|
1401
|
+
/** STRK denominations (18 decimals) */
|
|
1402
|
+
declare const STRK_DENOMINATIONS: readonly bigint[];
|
|
1403
|
+
/** USDC denominations (6 decimals) */
|
|
1404
|
+
declare const USDC_DENOMINATIONS: readonly bigint[];
|
|
1405
|
+
/** All denomination lists by VM31 asset ID */
|
|
1406
|
+
declare const VM31_DENOMINATIONS: Record<number, readonly bigint[]>;
|
|
1407
|
+
/** Denomination lists by token symbol */
|
|
1408
|
+
declare const DENOMINATION_BY_SYMBOL: Record<string, readonly bigint[]>;
|
|
1409
|
+
/**
|
|
1410
|
+
* Validate that a deposit amount is a standard denomination.
|
|
1411
|
+
* Throws if the amount is not in the whitelist.
|
|
1412
|
+
* Unknown assets pass through (forward-compatible).
|
|
1413
|
+
*
|
|
1414
|
+
* @param amount - Amount in base units (e.g., wei, satoshis)
|
|
1415
|
+
* @param assetIdOrSymbol - VM31 asset ID (0-4) or token symbol
|
|
1416
|
+
*/
|
|
1417
|
+
declare function validateDenomination(amount: bigint, assetIdOrSymbol: number | string): void;
|
|
1418
|
+
/**
|
|
1419
|
+
* Split an amount into the fewest standard denominations (greedy, largest first).
|
|
1420
|
+
* Useful for automatically batching a deposit into multiple denomination-safe transactions.
|
|
1421
|
+
*
|
|
1422
|
+
* @returns denominations array and any remainder that can't be represented
|
|
1423
|
+
*/
|
|
1424
|
+
declare function splitIntoDenominations(amount: bigint, assetIdOrSymbol: number | string): {
|
|
1425
|
+
denominations: bigint[];
|
|
1426
|
+
remainder: bigint;
|
|
1427
|
+
};
|
|
1428
|
+
/**
|
|
1429
|
+
* Get valid denominations for an asset.
|
|
1430
|
+
* Returns undefined for unknown assets.
|
|
1431
|
+
*/
|
|
1432
|
+
declare function getDenominations(assetIdOrSymbol: number | string): readonly bigint[] | undefined;
|
|
1433
|
+
|
|
1434
|
+
export { type AssetPair, type BatchStatus, type BridgeConfig, type ClaimFillParams, type ClaimParams, type CommitOrderParams, ConfidentialTransferClient, DARKPOOL_ASSET_IDS, DENOMINATION_BY_SYMBOL, DarkPoolClient, type DarkPoolDepositParams, type DarkPoolOrderData, type DepositParams, type DepositResult, type ECIESEnvelope, ECPoint, ETH_DENOMINATIONS, type EpochInfo, type FundParams, type GpuTier, MAINNET_PRIVACY_POOLS, MAINNET_TOKENS, type OTCOrder, OTCOrderbookClient, type OTCTrade, ObelyskClient, type ObelyskConfig, type ObelyskNetwork, ObelyskPrivacy, OrderSide, OrderStatus, OrderType, type OrderbookConfig, type OrderbookDepth, type OrderbookDepthLevel, type PackedDigest, type PlaceLimitOrderParams, type PlaceMarketOrderParams, type PrivacyNote, PrivacyPoolClient, PrivacyRouterClient, type PrivateAccount, ProverStakingClient, type RelayerInfo, type RevealOrderParams, SAGE_DENOMINATIONS, STRK_DENOMINATIONS, ShieldedSwapClient, type ShieldedSwapParams, type StakingConfig, type Stats24h, type StealthAnnouncement, StealthClient, type StealthMetaAddress, type StealthSendParams, type StealthSpendingProof, TOKEN_DECIMALS, type TradingPair, type TransferParams, USDC_DENOMINATIONS, type VM31AssetId, VM31BridgeClient, VM31VaultClient, VM31_ASSET_IDS, VM31_DENOMINATIONS, type VaultBatchInfo, type VaultDepositParams, type VaultMerklePath, type VaultNote, type VaultSubmitResult, type VaultTransferParams, type VaultWithdrawParams, WBTC_DENOMINATIONS, type WithdrawCTParams, type WithdrawParams, type WithdrawResult, type WorkerStake, commitmentToHash, createAEHint, createEncryptionProof, deriveNullifier, ecAdd, ecMul, eciesEncrypt, elgamalEncrypt, formatAmount, getContracts, getDenominations, getRpcUrl, mod, modInverse, parseAmount, pedersenCommit, randomScalar, splitIntoDenominations, validateDenomination };
|
package/dist/obelysk/index.js
CHANGED
|
@@ -23,7 +23,9 @@ __export(obelysk_exports, {
|
|
|
23
23
|
CURVE_ORDER: () => CURVE_ORDER,
|
|
24
24
|
ConfidentialTransferClient: () => ConfidentialTransferClient,
|
|
25
25
|
DARKPOOL_ASSET_IDS: () => DARKPOOL_ASSET_IDS,
|
|
26
|
+
DENOMINATION_BY_SYMBOL: () => DENOMINATION_BY_SYMBOL,
|
|
26
27
|
DarkPoolClient: () => DarkPoolClient,
|
|
28
|
+
ETH_DENOMINATIONS: () => ETH_DENOMINATIONS,
|
|
27
29
|
FIELD_PRIME: () => FIELD_PRIME,
|
|
28
30
|
GENERATOR_G: () => GENERATOR_G,
|
|
29
31
|
GENERATOR_H: () => GENERATOR_H,
|
|
@@ -38,27 +40,36 @@ __export(obelysk_exports, {
|
|
|
38
40
|
PrivacyPoolClient: () => PrivacyPoolClient,
|
|
39
41
|
PrivacyRouterClient: () => PrivacyRouterClient,
|
|
40
42
|
ProverStakingClient: () => ProverStakingClient,
|
|
43
|
+
SAGE_DENOMINATIONS: () => SAGE_DENOMINATIONS,
|
|
44
|
+
STRK_DENOMINATIONS: () => STRK_DENOMINATIONS,
|
|
41
45
|
ShieldedSwapClient: () => ShieldedSwapClient,
|
|
42
46
|
StealthClient: () => StealthClient,
|
|
43
47
|
TOKEN_DECIMALS: () => TOKEN_DECIMALS,
|
|
48
|
+
USDC_DENOMINATIONS: () => USDC_DENOMINATIONS,
|
|
44
49
|
VM31BridgeClient: () => VM31BridgeClient,
|
|
45
50
|
VM31VaultClient: () => VM31VaultClient,
|
|
46
51
|
VM31_ASSET_IDS: () => VM31_ASSET_IDS,
|
|
52
|
+
VM31_DENOMINATIONS: () => VM31_DENOMINATIONS,
|
|
53
|
+
WBTC_DENOMINATIONS: () => WBTC_DENOMINATIONS,
|
|
47
54
|
commitmentToHash: () => commitmentToHash,
|
|
48
55
|
createAEHint: () => createAEHint,
|
|
49
56
|
createEncryptionProof: () => createEncryptionProof,
|
|
50
57
|
deriveNullifier: () => deriveNullifier,
|
|
51
58
|
ecAdd: () => ecAdd2,
|
|
52
59
|
ecMul: () => ecMul2,
|
|
60
|
+
eciesEncrypt: () => eciesEncrypt,
|
|
53
61
|
elgamalEncrypt: () => elgamalEncrypt,
|
|
54
62
|
formatAmount: () => formatAmount,
|
|
55
63
|
getContracts: () => getContracts,
|
|
64
|
+
getDenominations: () => getDenominations,
|
|
56
65
|
getRpcUrl: () => getRpcUrl,
|
|
57
66
|
mod: () => mod,
|
|
58
67
|
modInverse: () => modInverse,
|
|
59
68
|
parseAmount: () => parseAmount,
|
|
60
69
|
pedersenCommit: () => pedersenCommit,
|
|
61
|
-
randomScalar: () => randomScalar2
|
|
70
|
+
randomScalar: () => randomScalar2,
|
|
71
|
+
splitIntoDenominations: () => splitIntoDenominations,
|
|
72
|
+
validateDenomination: () => validateDenomination
|
|
62
73
|
});
|
|
63
74
|
module.exports = __toCommonJS(obelysk_exports);
|
|
64
75
|
|
|
@@ -2104,6 +2115,225 @@ var ShieldedSwapClient = class {
|
|
|
2104
2115
|
}
|
|
2105
2116
|
};
|
|
2106
2117
|
|
|
2118
|
+
// src/obelysk/ecies.ts
|
|
2119
|
+
var HKDF_INFO = "obelysk-ecies-v1";
|
|
2120
|
+
var ECIES_VERSION = 1;
|
|
2121
|
+
async function eciesEncrypt(payload, relayerPubkeyHex) {
|
|
2122
|
+
const subtle = getCrypto();
|
|
2123
|
+
const relayerPubkeyBytes = hexToBytes(relayerPubkeyHex);
|
|
2124
|
+
if (relayerPubkeyBytes.length !== 32) {
|
|
2125
|
+
throw new Error(`Invalid relayer public key length: ${relayerPubkeyBytes.length} (expected 32)`);
|
|
2126
|
+
}
|
|
2127
|
+
const relayerPubkey = await subtle.importKey(
|
|
2128
|
+
"raw",
|
|
2129
|
+
relayerPubkeyBytes.buffer,
|
|
2130
|
+
{ name: "X25519" },
|
|
2131
|
+
false,
|
|
2132
|
+
[]
|
|
2133
|
+
);
|
|
2134
|
+
const ephemeralKeyPair = await subtle.generateKey(
|
|
2135
|
+
{ name: "X25519" },
|
|
2136
|
+
true,
|
|
2137
|
+
["deriveBits"]
|
|
2138
|
+
);
|
|
2139
|
+
const sharedBits = await subtle.deriveBits(
|
|
2140
|
+
{ name: "X25519", public: relayerPubkey },
|
|
2141
|
+
ephemeralKeyPair.privateKey,
|
|
2142
|
+
256
|
|
2143
|
+
);
|
|
2144
|
+
const sharedKey = await subtle.importKey(
|
|
2145
|
+
"raw",
|
|
2146
|
+
sharedBits,
|
|
2147
|
+
{ name: "HKDF" },
|
|
2148
|
+
false,
|
|
2149
|
+
["deriveKey"]
|
|
2150
|
+
);
|
|
2151
|
+
const aesKey = await subtle.deriveKey(
|
|
2152
|
+
{
|
|
2153
|
+
name: "HKDF",
|
|
2154
|
+
hash: "SHA-256",
|
|
2155
|
+
salt: new ArrayBuffer(0),
|
|
2156
|
+
info: new TextEncoder().encode(HKDF_INFO)
|
|
2157
|
+
},
|
|
2158
|
+
sharedKey,
|
|
2159
|
+
{ name: "AES-GCM", length: 256 },
|
|
2160
|
+
false,
|
|
2161
|
+
["encrypt"]
|
|
2162
|
+
);
|
|
2163
|
+
const nonce = getRandomBytes(12);
|
|
2164
|
+
const plaintext = new TextEncoder().encode(JSON.stringify(payload));
|
|
2165
|
+
const ciphertext = await subtle.encrypt(
|
|
2166
|
+
{ name: "AES-GCM", iv: nonce },
|
|
2167
|
+
aesKey,
|
|
2168
|
+
plaintext
|
|
2169
|
+
);
|
|
2170
|
+
const ephPubRaw = await subtle.exportKey("raw", ephemeralKeyPair.publicKey);
|
|
2171
|
+
return {
|
|
2172
|
+
ephemeral_pubkey: bytesToHex(new Uint8Array(ephPubRaw)),
|
|
2173
|
+
ciphertext: bytesToBase64(new Uint8Array(ciphertext)),
|
|
2174
|
+
nonce: bytesToHex(nonce),
|
|
2175
|
+
version: ECIES_VERSION
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
function getCrypto() {
|
|
2179
|
+
if (typeof globalThis.crypto?.subtle !== "undefined") {
|
|
2180
|
+
return globalThis.crypto.subtle;
|
|
2181
|
+
}
|
|
2182
|
+
try {
|
|
2183
|
+
const { webcrypto } = require("crypto");
|
|
2184
|
+
return webcrypto.subtle;
|
|
2185
|
+
} catch {
|
|
2186
|
+
throw new Error("ECIES requires Web Crypto API (Node 20+ or a modern browser)");
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
function getRandomBytes(n) {
|
|
2190
|
+
if (typeof globalThis.crypto?.getRandomValues !== "undefined") {
|
|
2191
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(n));
|
|
2192
|
+
}
|
|
2193
|
+
const { randomBytes: randomBytes2 } = require("crypto");
|
|
2194
|
+
return new Uint8Array(randomBytes2(n));
|
|
2195
|
+
}
|
|
2196
|
+
function hexToBytes(hex) {
|
|
2197
|
+
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
2198
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
2199
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2200
|
+
bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
2201
|
+
}
|
|
2202
|
+
return bytes;
|
|
2203
|
+
}
|
|
2204
|
+
function bytesToHex(bytes) {
|
|
2205
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2206
|
+
}
|
|
2207
|
+
function bytesToBase64(bytes) {
|
|
2208
|
+
if (typeof btoa === "function") {
|
|
2209
|
+
return btoa(String.fromCharCode(...bytes));
|
|
2210
|
+
}
|
|
2211
|
+
return Buffer.from(bytes).toString("base64");
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
// src/obelysk/denominations.ts
|
|
2215
|
+
var WBTC_DENOMINATIONS = [
|
|
2216
|
+
50000n,
|
|
2217
|
+
// 0.0005 BTC
|
|
2218
|
+
100000n,
|
|
2219
|
+
// 0.001 BTC
|
|
2220
|
+
500000n,
|
|
2221
|
+
// 0.005 BTC
|
|
2222
|
+
1000000n,
|
|
2223
|
+
// 0.01 BTC
|
|
2224
|
+
5000000n,
|
|
2225
|
+
// 0.05 BTC
|
|
2226
|
+
10000000n
|
|
2227
|
+
// 0.1 BTC
|
|
2228
|
+
];
|
|
2229
|
+
var SAGE_DENOMINATIONS = [
|
|
2230
|
+
10000000000000000n,
|
|
2231
|
+
// 0.01 SAGE
|
|
2232
|
+
50000000000000000n,
|
|
2233
|
+
// 0.05 SAGE
|
|
2234
|
+
100000000000000000n,
|
|
2235
|
+
// 0.1 SAGE
|
|
2236
|
+
500000000000000000n,
|
|
2237
|
+
// 0.5 SAGE
|
|
2238
|
+
1000000000000000000n,
|
|
2239
|
+
// 1 SAGE
|
|
2240
|
+
5000000000000000000n
|
|
2241
|
+
// 5 SAGE
|
|
2242
|
+
];
|
|
2243
|
+
var ETH_DENOMINATIONS = [
|
|
2244
|
+
1000000000000000n,
|
|
2245
|
+
// 0.001 ETH
|
|
2246
|
+
5000000000000000n,
|
|
2247
|
+
// 0.005 ETH
|
|
2248
|
+
10000000000000000n,
|
|
2249
|
+
// 0.01 ETH
|
|
2250
|
+
50000000000000000n,
|
|
2251
|
+
// 0.05 ETH
|
|
2252
|
+
100000000000000000n,
|
|
2253
|
+
// 0.1 ETH
|
|
2254
|
+
500000000000000000n
|
|
2255
|
+
// 0.5 ETH
|
|
2256
|
+
];
|
|
2257
|
+
var STRK_DENOMINATIONS = [
|
|
2258
|
+
50000000000000000n,
|
|
2259
|
+
// 0.05 STRK
|
|
2260
|
+
100000000000000000n,
|
|
2261
|
+
// 0.1 STRK
|
|
2262
|
+
500000000000000000n,
|
|
2263
|
+
// 0.5 STRK
|
|
2264
|
+
1000000000000000000n,
|
|
2265
|
+
// 1 STRK
|
|
2266
|
+
5000000000000000000n
|
|
2267
|
+
// 5 STRK
|
|
2268
|
+
];
|
|
2269
|
+
var USDC_DENOMINATIONS = [
|
|
2270
|
+
1000000n,
|
|
2271
|
+
// 1 USDC
|
|
2272
|
+
5000000n,
|
|
2273
|
+
// 5 USDC
|
|
2274
|
+
10000000n,
|
|
2275
|
+
// 10 USDC
|
|
2276
|
+
50000000n,
|
|
2277
|
+
// 50 USDC
|
|
2278
|
+
100000000n,
|
|
2279
|
+
// 100 USDC
|
|
2280
|
+
500000000n
|
|
2281
|
+
// 500 USDC
|
|
2282
|
+
];
|
|
2283
|
+
var VM31_DENOMINATIONS = {
|
|
2284
|
+
0: WBTC_DENOMINATIONS,
|
|
2285
|
+
1: SAGE_DENOMINATIONS,
|
|
2286
|
+
2: ETH_DENOMINATIONS,
|
|
2287
|
+
3: STRK_DENOMINATIONS,
|
|
2288
|
+
4: USDC_DENOMINATIONS
|
|
2289
|
+
};
|
|
2290
|
+
var DENOMINATION_BY_SYMBOL = {
|
|
2291
|
+
wbtc: WBTC_DENOMINATIONS,
|
|
2292
|
+
sage: SAGE_DENOMINATIONS,
|
|
2293
|
+
eth: ETH_DENOMINATIONS,
|
|
2294
|
+
strk: STRK_DENOMINATIONS,
|
|
2295
|
+
usdc: USDC_DENOMINATIONS
|
|
2296
|
+
};
|
|
2297
|
+
function validateDenomination(amount, assetIdOrSymbol) {
|
|
2298
|
+
let denoms;
|
|
2299
|
+
if (typeof assetIdOrSymbol === "number") {
|
|
2300
|
+
denoms = VM31_DENOMINATIONS[assetIdOrSymbol];
|
|
2301
|
+
} else {
|
|
2302
|
+
denoms = DENOMINATION_BY_SYMBOL[assetIdOrSymbol.toLowerCase()];
|
|
2303
|
+
}
|
|
2304
|
+
if (!denoms) return;
|
|
2305
|
+
if (!denoms.includes(amount)) {
|
|
2306
|
+
throw new Error(
|
|
2307
|
+
`Deposit must use a standard denomination for asset ${assetIdOrSymbol}. Got ${amount}. Valid: [${denoms.join(", ")}]`
|
|
2308
|
+
);
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
function splitIntoDenominations(amount, assetIdOrSymbol) {
|
|
2312
|
+
let denoms;
|
|
2313
|
+
if (typeof assetIdOrSymbol === "number") {
|
|
2314
|
+
denoms = VM31_DENOMINATIONS[assetIdOrSymbol];
|
|
2315
|
+
} else {
|
|
2316
|
+
denoms = DENOMINATION_BY_SYMBOL[assetIdOrSymbol.toLowerCase()];
|
|
2317
|
+
}
|
|
2318
|
+
if (!denoms) return { denominations: [amount], remainder: 0n };
|
|
2319
|
+
const sorted = [...denoms].sort((a, b) => b > a ? 1 : b < a ? -1 : 0);
|
|
2320
|
+
const result = [];
|
|
2321
|
+
let remaining = amount;
|
|
2322
|
+
for (const denom of sorted) {
|
|
2323
|
+
while (remaining >= denom) {
|
|
2324
|
+
result.push(denom);
|
|
2325
|
+
remaining -= denom;
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
return { denominations: result, remainder: remaining };
|
|
2329
|
+
}
|
|
2330
|
+
function getDenominations(assetIdOrSymbol) {
|
|
2331
|
+
if (typeof assetIdOrSymbol === "number") {
|
|
2332
|
+
return VM31_DENOMINATIONS[assetIdOrSymbol];
|
|
2333
|
+
}
|
|
2334
|
+
return DENOMINATION_BY_SYMBOL[assetIdOrSymbol.toLowerCase()];
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2107
2337
|
// src/obelysk/vm31Vault.ts
|
|
2108
2338
|
var VM31VaultClient = class {
|
|
2109
2339
|
constructor(obelysk) {
|
|
@@ -2118,6 +2348,8 @@ var VM31VaultClient = class {
|
|
|
2118
2348
|
get relayerApiKey() {
|
|
2119
2349
|
return this.obelysk.relayerApiKey;
|
|
2120
2350
|
}
|
|
2351
|
+
/** Cached relayer X25519 public key (fetched on first encrypted submit) */
|
|
2352
|
+
_relayerPubkey = null;
|
|
2121
2353
|
async relayerFetch(path, init) {
|
|
2122
2354
|
const url = `${this.relayerUrl}${path}`;
|
|
2123
2355
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -2129,6 +2361,27 @@ var VM31VaultClient = class {
|
|
|
2129
2361
|
}
|
|
2130
2362
|
return res.json();
|
|
2131
2363
|
}
|
|
2364
|
+
/**
|
|
2365
|
+
* Submit a payload to the relayer, encrypted with ECIES.
|
|
2366
|
+
* Falls back to plaintext if `encrypt: false` is passed.
|
|
2367
|
+
*/
|
|
2368
|
+
async relayerSubmit(payload, encrypt = true) {
|
|
2369
|
+
if (!encrypt) {
|
|
2370
|
+
return this.relayerFetch("/submit", {
|
|
2371
|
+
method: "POST",
|
|
2372
|
+
body: JSON.stringify(payload)
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2375
|
+
if (!this._relayerPubkey) {
|
|
2376
|
+
const keyInfo = await this.getRelayerPublicKey();
|
|
2377
|
+
this._relayerPubkey = keyInfo.publicKey;
|
|
2378
|
+
}
|
|
2379
|
+
const envelope = await eciesEncrypt(payload, this._relayerPubkey);
|
|
2380
|
+
return this.relayerFetch("/submit", {
|
|
2381
|
+
method: "POST",
|
|
2382
|
+
body: JSON.stringify(envelope)
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2132
2385
|
// --------------------------------------------------------------------------
|
|
2133
2386
|
// On-chain reads (callContract to vm31_pool)
|
|
2134
2387
|
// --------------------------------------------------------------------------
|
|
@@ -2292,61 +2545,65 @@ var VM31VaultClient = class {
|
|
|
2292
2545
|
algorithm: data.algorithm
|
|
2293
2546
|
};
|
|
2294
2547
|
}
|
|
2295
|
-
/**
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2548
|
+
/**
|
|
2549
|
+
* Submit a deposit transaction to the relayer.
|
|
2550
|
+
* Validates denomination (privacy gap #7) and encrypts with ECIES by default.
|
|
2551
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
2552
|
+
*/
|
|
2553
|
+
async submitDeposit(params, encrypt = true) {
|
|
2554
|
+
validateDenomination(params.amount, params.assetId);
|
|
2555
|
+
return this.relayerSubmit({
|
|
2556
|
+
type: "deposit",
|
|
2557
|
+
amount: Number(params.amount),
|
|
2558
|
+
asset_id: params.assetId,
|
|
2559
|
+
recipient_pubkey: params.recipientPubkey,
|
|
2560
|
+
recipient_viewing_key: params.recipientViewingKey
|
|
2561
|
+
}, encrypt);
|
|
2562
|
+
}
|
|
2563
|
+
/**
|
|
2564
|
+
* Submit a withdrawal transaction to the relayer.
|
|
2565
|
+
* Withdrawals are not denomination-restricted.
|
|
2566
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
2567
|
+
*/
|
|
2568
|
+
async submitWithdraw(params, encrypt = true) {
|
|
2569
|
+
return this.relayerSubmit({
|
|
2570
|
+
type: "withdraw",
|
|
2571
|
+
amount: Number(params.amount),
|
|
2572
|
+
asset_id: params.assetId,
|
|
2573
|
+
note: {
|
|
2574
|
+
owner_pubkey: params.note.owner_pubkey,
|
|
2575
|
+
asset_id: params.note.asset_id,
|
|
2576
|
+
amount_lo: params.note.amount_lo,
|
|
2577
|
+
amount_hi: params.note.amount_hi,
|
|
2578
|
+
blinding: params.note.blinding
|
|
2579
|
+
},
|
|
2580
|
+
spending_key: params.spendingKey,
|
|
2581
|
+
merkle_path: params.merklePath,
|
|
2582
|
+
merkle_root: params.merkleRoot,
|
|
2583
|
+
withdrawal_binding: params.withdrawalBinding,
|
|
2584
|
+
binding_salt: params.bindingSalt
|
|
2585
|
+
}, encrypt);
|
|
2586
|
+
}
|
|
2587
|
+
/**
|
|
2588
|
+
* Submit a private transfer transaction to the relayer.
|
|
2589
|
+
* Transfers are not denomination-restricted.
|
|
2590
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
2591
|
+
*/
|
|
2592
|
+
async submitTransfer(params, encrypt = true) {
|
|
2593
|
+
return this.relayerSubmit({
|
|
2594
|
+
type: "transfer",
|
|
2595
|
+
amount: Number(params.amount),
|
|
2596
|
+
asset_id: params.assetId,
|
|
2597
|
+
recipient_pubkey: params.recipientPubkey,
|
|
2598
|
+
recipient_viewing_key: params.recipientViewingKey,
|
|
2599
|
+
sender_viewing_key: params.senderViewingKey,
|
|
2600
|
+
input_notes: params.inputNotes.map((n) => ({
|
|
2601
|
+
note: n.note,
|
|
2602
|
+
spending_key: n.spendingKey,
|
|
2603
|
+
merkle_path: n.merklePath
|
|
2604
|
+
})),
|
|
2605
|
+
merkle_root: params.merkleRoot
|
|
2606
|
+
}, encrypt);
|
|
2350
2607
|
}
|
|
2351
2608
|
/** Query batch info from the relayer */
|
|
2352
2609
|
async queryBatch(batchId) {
|
|
@@ -3064,7 +3321,9 @@ var ObelyskClient = class {
|
|
|
3064
3321
|
CURVE_ORDER,
|
|
3065
3322
|
ConfidentialTransferClient,
|
|
3066
3323
|
DARKPOOL_ASSET_IDS,
|
|
3324
|
+
DENOMINATION_BY_SYMBOL,
|
|
3067
3325
|
DarkPoolClient,
|
|
3326
|
+
ETH_DENOMINATIONS,
|
|
3068
3327
|
FIELD_PRIME,
|
|
3069
3328
|
GENERATOR_G,
|
|
3070
3329
|
GENERATOR_H,
|
|
@@ -3079,25 +3338,34 @@ var ObelyskClient = class {
|
|
|
3079
3338
|
PrivacyPoolClient,
|
|
3080
3339
|
PrivacyRouterClient,
|
|
3081
3340
|
ProverStakingClient,
|
|
3341
|
+
SAGE_DENOMINATIONS,
|
|
3342
|
+
STRK_DENOMINATIONS,
|
|
3082
3343
|
ShieldedSwapClient,
|
|
3083
3344
|
StealthClient,
|
|
3084
3345
|
TOKEN_DECIMALS,
|
|
3346
|
+
USDC_DENOMINATIONS,
|
|
3085
3347
|
VM31BridgeClient,
|
|
3086
3348
|
VM31VaultClient,
|
|
3087
3349
|
VM31_ASSET_IDS,
|
|
3350
|
+
VM31_DENOMINATIONS,
|
|
3351
|
+
WBTC_DENOMINATIONS,
|
|
3088
3352
|
commitmentToHash,
|
|
3089
3353
|
createAEHint,
|
|
3090
3354
|
createEncryptionProof,
|
|
3091
3355
|
deriveNullifier,
|
|
3092
3356
|
ecAdd,
|
|
3093
3357
|
ecMul,
|
|
3358
|
+
eciesEncrypt,
|
|
3094
3359
|
elgamalEncrypt,
|
|
3095
3360
|
formatAmount,
|
|
3096
3361
|
getContracts,
|
|
3362
|
+
getDenominations,
|
|
3097
3363
|
getRpcUrl,
|
|
3098
3364
|
mod,
|
|
3099
3365
|
modInverse,
|
|
3100
3366
|
parseAmount,
|
|
3101
3367
|
pedersenCommit,
|
|
3102
|
-
randomScalar
|
|
3368
|
+
randomScalar,
|
|
3369
|
+
splitIntoDenominations,
|
|
3370
|
+
validateDenomination
|
|
3103
3371
|
});
|
package/dist/obelysk/index.mjs
CHANGED
|
@@ -4,11 +4,12 @@ import {
|
|
|
4
4
|
GENERATOR_G,
|
|
5
5
|
GENERATOR_H,
|
|
6
6
|
ObelyskPrivacy,
|
|
7
|
+
__require,
|
|
7
8
|
ecAdd,
|
|
8
9
|
ecMul,
|
|
9
10
|
invMod,
|
|
10
11
|
randomScalar
|
|
11
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-CGPFHXUF.mjs";
|
|
12
13
|
|
|
13
14
|
// src/obelysk/client.ts
|
|
14
15
|
import { RpcProvider } from "starknet";
|
|
@@ -1788,6 +1789,225 @@ var ShieldedSwapClient = class {
|
|
|
1788
1789
|
}
|
|
1789
1790
|
};
|
|
1790
1791
|
|
|
1792
|
+
// src/obelysk/ecies.ts
|
|
1793
|
+
var HKDF_INFO = "obelysk-ecies-v1";
|
|
1794
|
+
var ECIES_VERSION = 1;
|
|
1795
|
+
async function eciesEncrypt(payload, relayerPubkeyHex) {
|
|
1796
|
+
const subtle = getCrypto();
|
|
1797
|
+
const relayerPubkeyBytes = hexToBytes(relayerPubkeyHex);
|
|
1798
|
+
if (relayerPubkeyBytes.length !== 32) {
|
|
1799
|
+
throw new Error(`Invalid relayer public key length: ${relayerPubkeyBytes.length} (expected 32)`);
|
|
1800
|
+
}
|
|
1801
|
+
const relayerPubkey = await subtle.importKey(
|
|
1802
|
+
"raw",
|
|
1803
|
+
relayerPubkeyBytes.buffer,
|
|
1804
|
+
{ name: "X25519" },
|
|
1805
|
+
false,
|
|
1806
|
+
[]
|
|
1807
|
+
);
|
|
1808
|
+
const ephemeralKeyPair = await subtle.generateKey(
|
|
1809
|
+
{ name: "X25519" },
|
|
1810
|
+
true,
|
|
1811
|
+
["deriveBits"]
|
|
1812
|
+
);
|
|
1813
|
+
const sharedBits = await subtle.deriveBits(
|
|
1814
|
+
{ name: "X25519", public: relayerPubkey },
|
|
1815
|
+
ephemeralKeyPair.privateKey,
|
|
1816
|
+
256
|
|
1817
|
+
);
|
|
1818
|
+
const sharedKey = await subtle.importKey(
|
|
1819
|
+
"raw",
|
|
1820
|
+
sharedBits,
|
|
1821
|
+
{ name: "HKDF" },
|
|
1822
|
+
false,
|
|
1823
|
+
["deriveKey"]
|
|
1824
|
+
);
|
|
1825
|
+
const aesKey = await subtle.deriveKey(
|
|
1826
|
+
{
|
|
1827
|
+
name: "HKDF",
|
|
1828
|
+
hash: "SHA-256",
|
|
1829
|
+
salt: new ArrayBuffer(0),
|
|
1830
|
+
info: new TextEncoder().encode(HKDF_INFO)
|
|
1831
|
+
},
|
|
1832
|
+
sharedKey,
|
|
1833
|
+
{ name: "AES-GCM", length: 256 },
|
|
1834
|
+
false,
|
|
1835
|
+
["encrypt"]
|
|
1836
|
+
);
|
|
1837
|
+
const nonce = getRandomBytes(12);
|
|
1838
|
+
const plaintext = new TextEncoder().encode(JSON.stringify(payload));
|
|
1839
|
+
const ciphertext = await subtle.encrypt(
|
|
1840
|
+
{ name: "AES-GCM", iv: nonce },
|
|
1841
|
+
aesKey,
|
|
1842
|
+
plaintext
|
|
1843
|
+
);
|
|
1844
|
+
const ephPubRaw = await subtle.exportKey("raw", ephemeralKeyPair.publicKey);
|
|
1845
|
+
return {
|
|
1846
|
+
ephemeral_pubkey: bytesToHex(new Uint8Array(ephPubRaw)),
|
|
1847
|
+
ciphertext: bytesToBase64(new Uint8Array(ciphertext)),
|
|
1848
|
+
nonce: bytesToHex(nonce),
|
|
1849
|
+
version: ECIES_VERSION
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
function getCrypto() {
|
|
1853
|
+
if (typeof globalThis.crypto?.subtle !== "undefined") {
|
|
1854
|
+
return globalThis.crypto.subtle;
|
|
1855
|
+
}
|
|
1856
|
+
try {
|
|
1857
|
+
const { webcrypto } = __require("crypto");
|
|
1858
|
+
return webcrypto.subtle;
|
|
1859
|
+
} catch {
|
|
1860
|
+
throw new Error("ECIES requires Web Crypto API (Node 20+ or a modern browser)");
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
function getRandomBytes(n) {
|
|
1864
|
+
if (typeof globalThis.crypto?.getRandomValues !== "undefined") {
|
|
1865
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(n));
|
|
1866
|
+
}
|
|
1867
|
+
const { randomBytes } = __require("crypto");
|
|
1868
|
+
return new Uint8Array(randomBytes(n));
|
|
1869
|
+
}
|
|
1870
|
+
function hexToBytes(hex) {
|
|
1871
|
+
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
1872
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
1873
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1874
|
+
bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
1875
|
+
}
|
|
1876
|
+
return bytes;
|
|
1877
|
+
}
|
|
1878
|
+
function bytesToHex(bytes) {
|
|
1879
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1880
|
+
}
|
|
1881
|
+
function bytesToBase64(bytes) {
|
|
1882
|
+
if (typeof btoa === "function") {
|
|
1883
|
+
return btoa(String.fromCharCode(...bytes));
|
|
1884
|
+
}
|
|
1885
|
+
return Buffer.from(bytes).toString("base64");
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
// src/obelysk/denominations.ts
|
|
1889
|
+
var WBTC_DENOMINATIONS = [
|
|
1890
|
+
50000n,
|
|
1891
|
+
// 0.0005 BTC
|
|
1892
|
+
100000n,
|
|
1893
|
+
// 0.001 BTC
|
|
1894
|
+
500000n,
|
|
1895
|
+
// 0.005 BTC
|
|
1896
|
+
1000000n,
|
|
1897
|
+
// 0.01 BTC
|
|
1898
|
+
5000000n,
|
|
1899
|
+
// 0.05 BTC
|
|
1900
|
+
10000000n
|
|
1901
|
+
// 0.1 BTC
|
|
1902
|
+
];
|
|
1903
|
+
var SAGE_DENOMINATIONS = [
|
|
1904
|
+
10000000000000000n,
|
|
1905
|
+
// 0.01 SAGE
|
|
1906
|
+
50000000000000000n,
|
|
1907
|
+
// 0.05 SAGE
|
|
1908
|
+
100000000000000000n,
|
|
1909
|
+
// 0.1 SAGE
|
|
1910
|
+
500000000000000000n,
|
|
1911
|
+
// 0.5 SAGE
|
|
1912
|
+
1000000000000000000n,
|
|
1913
|
+
// 1 SAGE
|
|
1914
|
+
5000000000000000000n
|
|
1915
|
+
// 5 SAGE
|
|
1916
|
+
];
|
|
1917
|
+
var ETH_DENOMINATIONS = [
|
|
1918
|
+
1000000000000000n,
|
|
1919
|
+
// 0.001 ETH
|
|
1920
|
+
5000000000000000n,
|
|
1921
|
+
// 0.005 ETH
|
|
1922
|
+
10000000000000000n,
|
|
1923
|
+
// 0.01 ETH
|
|
1924
|
+
50000000000000000n,
|
|
1925
|
+
// 0.05 ETH
|
|
1926
|
+
100000000000000000n,
|
|
1927
|
+
// 0.1 ETH
|
|
1928
|
+
500000000000000000n
|
|
1929
|
+
// 0.5 ETH
|
|
1930
|
+
];
|
|
1931
|
+
var STRK_DENOMINATIONS = [
|
|
1932
|
+
50000000000000000n,
|
|
1933
|
+
// 0.05 STRK
|
|
1934
|
+
100000000000000000n,
|
|
1935
|
+
// 0.1 STRK
|
|
1936
|
+
500000000000000000n,
|
|
1937
|
+
// 0.5 STRK
|
|
1938
|
+
1000000000000000000n,
|
|
1939
|
+
// 1 STRK
|
|
1940
|
+
5000000000000000000n
|
|
1941
|
+
// 5 STRK
|
|
1942
|
+
];
|
|
1943
|
+
var USDC_DENOMINATIONS = [
|
|
1944
|
+
1000000n,
|
|
1945
|
+
// 1 USDC
|
|
1946
|
+
5000000n,
|
|
1947
|
+
// 5 USDC
|
|
1948
|
+
10000000n,
|
|
1949
|
+
// 10 USDC
|
|
1950
|
+
50000000n,
|
|
1951
|
+
// 50 USDC
|
|
1952
|
+
100000000n,
|
|
1953
|
+
// 100 USDC
|
|
1954
|
+
500000000n
|
|
1955
|
+
// 500 USDC
|
|
1956
|
+
];
|
|
1957
|
+
var VM31_DENOMINATIONS = {
|
|
1958
|
+
0: WBTC_DENOMINATIONS,
|
|
1959
|
+
1: SAGE_DENOMINATIONS,
|
|
1960
|
+
2: ETH_DENOMINATIONS,
|
|
1961
|
+
3: STRK_DENOMINATIONS,
|
|
1962
|
+
4: USDC_DENOMINATIONS
|
|
1963
|
+
};
|
|
1964
|
+
var DENOMINATION_BY_SYMBOL = {
|
|
1965
|
+
wbtc: WBTC_DENOMINATIONS,
|
|
1966
|
+
sage: SAGE_DENOMINATIONS,
|
|
1967
|
+
eth: ETH_DENOMINATIONS,
|
|
1968
|
+
strk: STRK_DENOMINATIONS,
|
|
1969
|
+
usdc: USDC_DENOMINATIONS
|
|
1970
|
+
};
|
|
1971
|
+
function validateDenomination(amount, assetIdOrSymbol) {
|
|
1972
|
+
let denoms;
|
|
1973
|
+
if (typeof assetIdOrSymbol === "number") {
|
|
1974
|
+
denoms = VM31_DENOMINATIONS[assetIdOrSymbol];
|
|
1975
|
+
} else {
|
|
1976
|
+
denoms = DENOMINATION_BY_SYMBOL[assetIdOrSymbol.toLowerCase()];
|
|
1977
|
+
}
|
|
1978
|
+
if (!denoms) return;
|
|
1979
|
+
if (!denoms.includes(amount)) {
|
|
1980
|
+
throw new Error(
|
|
1981
|
+
`Deposit must use a standard denomination for asset ${assetIdOrSymbol}. Got ${amount}. Valid: [${denoms.join(", ")}]`
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
function splitIntoDenominations(amount, assetIdOrSymbol) {
|
|
1986
|
+
let denoms;
|
|
1987
|
+
if (typeof assetIdOrSymbol === "number") {
|
|
1988
|
+
denoms = VM31_DENOMINATIONS[assetIdOrSymbol];
|
|
1989
|
+
} else {
|
|
1990
|
+
denoms = DENOMINATION_BY_SYMBOL[assetIdOrSymbol.toLowerCase()];
|
|
1991
|
+
}
|
|
1992
|
+
if (!denoms) return { denominations: [amount], remainder: 0n };
|
|
1993
|
+
const sorted = [...denoms].sort((a, b) => b > a ? 1 : b < a ? -1 : 0);
|
|
1994
|
+
const result = [];
|
|
1995
|
+
let remaining = amount;
|
|
1996
|
+
for (const denom of sorted) {
|
|
1997
|
+
while (remaining >= denom) {
|
|
1998
|
+
result.push(denom);
|
|
1999
|
+
remaining -= denom;
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
return { denominations: result, remainder: remaining };
|
|
2003
|
+
}
|
|
2004
|
+
function getDenominations(assetIdOrSymbol) {
|
|
2005
|
+
if (typeof assetIdOrSymbol === "number") {
|
|
2006
|
+
return VM31_DENOMINATIONS[assetIdOrSymbol];
|
|
2007
|
+
}
|
|
2008
|
+
return DENOMINATION_BY_SYMBOL[assetIdOrSymbol.toLowerCase()];
|
|
2009
|
+
}
|
|
2010
|
+
|
|
1791
2011
|
// src/obelysk/vm31Vault.ts
|
|
1792
2012
|
var VM31VaultClient = class {
|
|
1793
2013
|
constructor(obelysk) {
|
|
@@ -1802,6 +2022,8 @@ var VM31VaultClient = class {
|
|
|
1802
2022
|
get relayerApiKey() {
|
|
1803
2023
|
return this.obelysk.relayerApiKey;
|
|
1804
2024
|
}
|
|
2025
|
+
/** Cached relayer X25519 public key (fetched on first encrypted submit) */
|
|
2026
|
+
_relayerPubkey = null;
|
|
1805
2027
|
async relayerFetch(path, init) {
|
|
1806
2028
|
const url = `${this.relayerUrl}${path}`;
|
|
1807
2029
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -1813,6 +2035,27 @@ var VM31VaultClient = class {
|
|
|
1813
2035
|
}
|
|
1814
2036
|
return res.json();
|
|
1815
2037
|
}
|
|
2038
|
+
/**
|
|
2039
|
+
* Submit a payload to the relayer, encrypted with ECIES.
|
|
2040
|
+
* Falls back to plaintext if `encrypt: false` is passed.
|
|
2041
|
+
*/
|
|
2042
|
+
async relayerSubmit(payload, encrypt = true) {
|
|
2043
|
+
if (!encrypt) {
|
|
2044
|
+
return this.relayerFetch("/submit", {
|
|
2045
|
+
method: "POST",
|
|
2046
|
+
body: JSON.stringify(payload)
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
if (!this._relayerPubkey) {
|
|
2050
|
+
const keyInfo = await this.getRelayerPublicKey();
|
|
2051
|
+
this._relayerPubkey = keyInfo.publicKey;
|
|
2052
|
+
}
|
|
2053
|
+
const envelope = await eciesEncrypt(payload, this._relayerPubkey);
|
|
2054
|
+
return this.relayerFetch("/submit", {
|
|
2055
|
+
method: "POST",
|
|
2056
|
+
body: JSON.stringify(envelope)
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
1816
2059
|
// --------------------------------------------------------------------------
|
|
1817
2060
|
// On-chain reads (callContract to vm31_pool)
|
|
1818
2061
|
// --------------------------------------------------------------------------
|
|
@@ -1976,61 +2219,65 @@ var VM31VaultClient = class {
|
|
|
1976
2219
|
algorithm: data.algorithm
|
|
1977
2220
|
};
|
|
1978
2221
|
}
|
|
1979
|
-
/**
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
2222
|
+
/**
|
|
2223
|
+
* Submit a deposit transaction to the relayer.
|
|
2224
|
+
* Validates denomination (privacy gap #7) and encrypts with ECIES by default.
|
|
2225
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
2226
|
+
*/
|
|
2227
|
+
async submitDeposit(params, encrypt = true) {
|
|
2228
|
+
validateDenomination(params.amount, params.assetId);
|
|
2229
|
+
return this.relayerSubmit({
|
|
2230
|
+
type: "deposit",
|
|
2231
|
+
amount: Number(params.amount),
|
|
2232
|
+
asset_id: params.assetId,
|
|
2233
|
+
recipient_pubkey: params.recipientPubkey,
|
|
2234
|
+
recipient_viewing_key: params.recipientViewingKey
|
|
2235
|
+
}, encrypt);
|
|
1991
2236
|
}
|
|
1992
|
-
/**
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2237
|
+
/**
|
|
2238
|
+
* Submit a withdrawal transaction to the relayer.
|
|
2239
|
+
* Withdrawals are not denomination-restricted.
|
|
2240
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
2241
|
+
*/
|
|
2242
|
+
async submitWithdraw(params, encrypt = true) {
|
|
2243
|
+
return this.relayerSubmit({
|
|
2244
|
+
type: "withdraw",
|
|
2245
|
+
amount: Number(params.amount),
|
|
2246
|
+
asset_id: params.assetId,
|
|
2247
|
+
note: {
|
|
2248
|
+
owner_pubkey: params.note.owner_pubkey,
|
|
2249
|
+
asset_id: params.note.asset_id,
|
|
2250
|
+
amount_lo: params.note.amount_lo,
|
|
2251
|
+
amount_hi: params.note.amount_hi,
|
|
2252
|
+
blinding: params.note.blinding
|
|
2253
|
+
},
|
|
2254
|
+
spending_key: params.spendingKey,
|
|
2255
|
+
merkle_path: params.merklePath,
|
|
2256
|
+
merkle_root: params.merkleRoot,
|
|
2257
|
+
withdrawal_binding: params.withdrawalBinding,
|
|
2258
|
+
binding_salt: params.bindingSalt
|
|
2259
|
+
}, encrypt);
|
|
2014
2260
|
}
|
|
2015
|
-
/**
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
})
|
|
2033
|
-
|
|
2261
|
+
/**
|
|
2262
|
+
* Submit a private transfer transaction to the relayer.
|
|
2263
|
+
* Transfers are not denomination-restricted.
|
|
2264
|
+
* @param encrypt - Set to false for legacy plaintext mode (default: true)
|
|
2265
|
+
*/
|
|
2266
|
+
async submitTransfer(params, encrypt = true) {
|
|
2267
|
+
return this.relayerSubmit({
|
|
2268
|
+
type: "transfer",
|
|
2269
|
+
amount: Number(params.amount),
|
|
2270
|
+
asset_id: params.assetId,
|
|
2271
|
+
recipient_pubkey: params.recipientPubkey,
|
|
2272
|
+
recipient_viewing_key: params.recipientViewingKey,
|
|
2273
|
+
sender_viewing_key: params.senderViewingKey,
|
|
2274
|
+
input_notes: params.inputNotes.map((n) => ({
|
|
2275
|
+
note: n.note,
|
|
2276
|
+
spending_key: n.spendingKey,
|
|
2277
|
+
merkle_path: n.merklePath
|
|
2278
|
+
})),
|
|
2279
|
+
merkle_root: params.merkleRoot
|
|
2280
|
+
}, encrypt);
|
|
2034
2281
|
}
|
|
2035
2282
|
/** Query batch info from the relayer */
|
|
2036
2283
|
async queryBatch(batchId) {
|
|
@@ -2747,7 +2994,9 @@ export {
|
|
|
2747
2994
|
CURVE_ORDER,
|
|
2748
2995
|
ConfidentialTransferClient,
|
|
2749
2996
|
DARKPOOL_ASSET_IDS,
|
|
2997
|
+
DENOMINATION_BY_SYMBOL,
|
|
2750
2998
|
DarkPoolClient,
|
|
2999
|
+
ETH_DENOMINATIONS,
|
|
2751
3000
|
FIELD_PRIME,
|
|
2752
3001
|
GENERATOR_G,
|
|
2753
3002
|
GENERATOR_H,
|
|
@@ -2762,25 +3011,34 @@ export {
|
|
|
2762
3011
|
PrivacyPoolClient,
|
|
2763
3012
|
PrivacyRouterClient,
|
|
2764
3013
|
ProverStakingClient,
|
|
3014
|
+
SAGE_DENOMINATIONS,
|
|
3015
|
+
STRK_DENOMINATIONS,
|
|
2765
3016
|
ShieldedSwapClient,
|
|
2766
3017
|
StealthClient,
|
|
2767
3018
|
TOKEN_DECIMALS,
|
|
3019
|
+
USDC_DENOMINATIONS,
|
|
2768
3020
|
VM31BridgeClient,
|
|
2769
3021
|
VM31VaultClient,
|
|
2770
3022
|
VM31_ASSET_IDS,
|
|
3023
|
+
VM31_DENOMINATIONS,
|
|
3024
|
+
WBTC_DENOMINATIONS,
|
|
2771
3025
|
commitmentToHash,
|
|
2772
3026
|
createAEHint,
|
|
2773
3027
|
createEncryptionProof,
|
|
2774
3028
|
deriveNullifier,
|
|
2775
3029
|
ecAdd2 as ecAdd,
|
|
2776
3030
|
ecMul2 as ecMul,
|
|
3031
|
+
eciesEncrypt,
|
|
2777
3032
|
elgamalEncrypt,
|
|
2778
3033
|
formatAmount,
|
|
2779
3034
|
getContracts,
|
|
3035
|
+
getDenominations,
|
|
2780
3036
|
getRpcUrl,
|
|
2781
3037
|
mod,
|
|
2782
3038
|
modInverse,
|
|
2783
3039
|
parseAmount,
|
|
2784
3040
|
pedersenCommit,
|
|
2785
|
-
randomScalar2 as randomScalar
|
|
3041
|
+
randomScalar2 as randomScalar,
|
|
3042
|
+
splitIntoDenominations,
|
|
3043
|
+
validateDenomination
|
|
2786
3044
|
};
|
package/dist/privacy/index.mjs
CHANGED
package/dist/react/index.mjs
CHANGED
package/package.json
CHANGED