@sip-protocol/sdk 0.7.3 → 0.8.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 +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +47556 -19603
- package/dist/browser.mjs +628 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
- package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48396 -19623
- package/dist/index.mjs +537 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +44 -11
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +252 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +47 -6
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +186 -33
- package/src/chains/solana/providers/index.ts +31 -0
- package/src/chains/solana/providers/interface.ts +61 -18
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +338 -67
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +83 -66
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +57 -6
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +23 -0
- package/src/compliance/range-sas.ts +398 -33
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +686 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +254 -4
- package/src/privacy-backends/interface.ts +649 -6
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash.ts +13 -17
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +414 -2
- package/src/privacy-backends/router.ts +283 -3
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +3 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +110 -29
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-2XIVXWHA.mjs +0 -1930
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-7RFRWDCW.mjs +0 -1504
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-F6F73W35.mjs +0 -16166
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-OFDBEIEK.mjs +0 -16166
- package/dist/chunk-SF7YSLF5.mjs +0 -1515
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/chunk-WWUSGOXE.mjs +0 -17129
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-B71aXVzk.d.ts +0 -13264
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-pOIIuwfV.d.mts +0 -13264
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-4O4K45VU.mjs +0 -46
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-NDABAZ6P.mjs +0 -56
- package/dist/solana-Q4NAVBTS.mjs +0 -46
- package/dist/solana-ZYO63LY5.mjs +0 -46
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ethereum Stealth Address Implementation (EIP-5564)
|
|
3
|
+
*
|
|
4
|
+
* Ethereum-specific wrapper around secp256k1 stealth addresses.
|
|
5
|
+
* Implements EIP-5564 compliant stealth address generation and resolution.
|
|
6
|
+
*
|
|
7
|
+
* ## EIP-5564 Overview
|
|
8
|
+
*
|
|
9
|
+
* EIP-5564 defines a standard for stealth addresses on Ethereum:
|
|
10
|
+
* - Meta-address format: `st:eth:0x<spendingKey><viewingKey>`
|
|
11
|
+
* - Scheme ID 1: secp256k1 curve
|
|
12
|
+
* - Uses keccak256 for address derivation
|
|
13
|
+
*
|
|
14
|
+
* @see https://eips.ethereum.org/EIPS/eip-5564
|
|
15
|
+
* @packageDocumentation
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type {
|
|
19
|
+
StealthMetaAddress,
|
|
20
|
+
StealthAddress,
|
|
21
|
+
StealthAddressRecovery,
|
|
22
|
+
HexString,
|
|
23
|
+
} from '@sip-protocol/types'
|
|
24
|
+
import {
|
|
25
|
+
generateSecp256k1StealthMetaAddress,
|
|
26
|
+
generateSecp256k1StealthAddress,
|
|
27
|
+
deriveSecp256k1StealthPrivateKey,
|
|
28
|
+
checkSecp256k1StealthAddress,
|
|
29
|
+
publicKeyToEthAddress,
|
|
30
|
+
} from '../../stealth/secp256k1'
|
|
31
|
+
import { ValidationError } from '../../errors'
|
|
32
|
+
import { SECP256K1_SCHEME_ID } from './constants'
|
|
33
|
+
|
|
34
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Ethereum stealth meta-address with additional context
|
|
38
|
+
*/
|
|
39
|
+
export interface EthereumStealthMetaAddress extends StealthMetaAddress {
|
|
40
|
+
/** Always 'ethereum' for this chain */
|
|
41
|
+
chain: 'ethereum'
|
|
42
|
+
/** EIP-5564 scheme ID (1 for secp256k1) */
|
|
43
|
+
schemeId: typeof SECP256K1_SCHEME_ID
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Ethereum stealth address with derived ETH address
|
|
48
|
+
*/
|
|
49
|
+
export interface EthereumStealthAddress extends StealthAddress {
|
|
50
|
+
/** Ethereum address derived from the stealth public key */
|
|
51
|
+
ethAddress: HexString
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Result of generating an Ethereum stealth meta-address
|
|
56
|
+
*/
|
|
57
|
+
export interface EthereumStealthMetaAddressResult {
|
|
58
|
+
/** The stealth meta-address */
|
|
59
|
+
metaAddress: EthereumStealthMetaAddress
|
|
60
|
+
/** EIP-5564 encoded string */
|
|
61
|
+
encoded: string
|
|
62
|
+
/** Spending private key (keep secret!) */
|
|
63
|
+
spendingPrivateKey: HexString
|
|
64
|
+
/** Viewing private key (share with auditors) */
|
|
65
|
+
viewingPrivateKey: HexString
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Result of resolving a stealth address for a recipient
|
|
70
|
+
*/
|
|
71
|
+
export interface EthereumStealthAddressResult {
|
|
72
|
+
/** The stealth address */
|
|
73
|
+
stealthAddress: EthereumStealthAddress
|
|
74
|
+
/** Shared secret (for debugging, should be discarded) */
|
|
75
|
+
sharedSecret: HexString
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* EIP-5564 meta-address prefix for Ethereum
|
|
82
|
+
*/
|
|
83
|
+
export const EIP5564_PREFIX = 'st:eth:0x'
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Scheme ID for secp256k1 (EIP-5564)
|
|
87
|
+
*/
|
|
88
|
+
export const SCHEME_ID = SECP256K1_SCHEME_ID
|
|
89
|
+
|
|
90
|
+
// ─── Meta-Address Generation ────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Generate a new Ethereum stealth meta-address
|
|
94
|
+
*
|
|
95
|
+
* Creates a new keypair suitable for receiving stealth payments on Ethereum.
|
|
96
|
+
*
|
|
97
|
+
* @param label - Optional label for the meta-address
|
|
98
|
+
* @returns Generated meta-address and private keys
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const result = generateEthereumStealthMetaAddress('My Wallet')
|
|
103
|
+
*
|
|
104
|
+
* // Share the encoded meta-address with senders
|
|
105
|
+
* console.log(result.encoded)
|
|
106
|
+
* // => 'st:eth:0x02abc...123def...456'
|
|
107
|
+
*
|
|
108
|
+
* // Store private keys securely
|
|
109
|
+
* console.log(result.spendingPrivateKey) // For claiming funds
|
|
110
|
+
* console.log(result.viewingPrivateKey) // For scanning & auditors
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export function generateEthereumStealthMetaAddress(
|
|
114
|
+
label?: string
|
|
115
|
+
): EthereumStealthMetaAddressResult {
|
|
116
|
+
const { metaAddress, spendingPrivateKey, viewingPrivateKey } =
|
|
117
|
+
generateSecp256k1StealthMetaAddress('ethereum', label)
|
|
118
|
+
|
|
119
|
+
const ethereumMetaAddress: EthereumStealthMetaAddress = {
|
|
120
|
+
...metaAddress,
|
|
121
|
+
chain: 'ethereum',
|
|
122
|
+
schemeId: SCHEME_ID,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
metaAddress: ethereumMetaAddress,
|
|
127
|
+
encoded: encodeEthereumStealthMetaAddress(ethereumMetaAddress),
|
|
128
|
+
spendingPrivateKey,
|
|
129
|
+
viewingPrivateKey,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ─── Meta-Address Encoding ──────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Encode an Ethereum stealth meta-address to EIP-5564 string format
|
|
137
|
+
*
|
|
138
|
+
* Format: `st:eth:0x<spendingKey><viewingKey>`
|
|
139
|
+
* - spendingKey: 33 bytes compressed secp256k1 (66 hex chars)
|
|
140
|
+
* - viewingKey: 33 bytes compressed secp256k1 (66 hex chars)
|
|
141
|
+
*
|
|
142
|
+
* @param metaAddress - The meta-address to encode
|
|
143
|
+
* @returns EIP-5564 encoded string
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const encoded = encodeEthereumStealthMetaAddress(metaAddress)
|
|
148
|
+
* // => 'st:eth:0x02abc...123def...456'
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export function encodeEthereumStealthMetaAddress(
|
|
152
|
+
metaAddress: StealthMetaAddress
|
|
153
|
+
): string {
|
|
154
|
+
// Remove 0x prefixes
|
|
155
|
+
const spendingKey = metaAddress.spendingKey.slice(2)
|
|
156
|
+
const viewingKey = metaAddress.viewingKey.slice(2)
|
|
157
|
+
|
|
158
|
+
// Validate lengths (33 bytes = 66 hex chars)
|
|
159
|
+
if (spendingKey.length !== 66) {
|
|
160
|
+
throw new ValidationError(
|
|
161
|
+
`spendingKey must be 33 bytes (66 hex chars), got ${spendingKey.length / 2} bytes`,
|
|
162
|
+
'metaAddress.spendingKey'
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (viewingKey.length !== 66) {
|
|
167
|
+
throw new ValidationError(
|
|
168
|
+
`viewingKey must be 33 bytes (66 hex chars), got ${viewingKey.length / 2} bytes`,
|
|
169
|
+
'metaAddress.viewingKey'
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return `${EIP5564_PREFIX}${spendingKey}${viewingKey}`
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Parse an EIP-5564 encoded meta-address string
|
|
178
|
+
*
|
|
179
|
+
* @param encoded - The encoded meta-address string
|
|
180
|
+
* @returns Parsed meta-address
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const metaAddress = parseEthereumStealthMetaAddress('st:eth:0x02abc...123def...456')
|
|
185
|
+
* console.log(metaAddress.spendingKey) // '0x02abc...123'
|
|
186
|
+
* console.log(metaAddress.viewingKey) // '0x03def...456'
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export function parseEthereumStealthMetaAddress(
|
|
190
|
+
encoded: string
|
|
191
|
+
): EthereumStealthMetaAddress {
|
|
192
|
+
if (!encoded || typeof encoded !== 'string') {
|
|
193
|
+
throw new ValidationError('must be a non-empty string', 'encoded')
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Check prefix
|
|
197
|
+
if (!encoded.startsWith(EIP5564_PREFIX)) {
|
|
198
|
+
throw new ValidationError(
|
|
199
|
+
`must start with '${EIP5564_PREFIX}', got '${encoded.slice(0, 10)}...'`,
|
|
200
|
+
'encoded'
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Extract keys (after 'st:eth:0x')
|
|
205
|
+
const keysHex = encoded.slice(EIP5564_PREFIX.length)
|
|
206
|
+
|
|
207
|
+
// Should be 132 hex chars (66 + 66 for two 33-byte keys)
|
|
208
|
+
if (keysHex.length !== 132) {
|
|
209
|
+
throw new ValidationError(
|
|
210
|
+
`expected 132 hex characters for keys, got ${keysHex.length}`,
|
|
211
|
+
'encoded'
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Validate hex
|
|
216
|
+
if (!/^[0-9a-fA-F]+$/.test(keysHex)) {
|
|
217
|
+
throw new ValidationError('contains invalid hex characters', 'encoded')
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const spendingKey = `0x${keysHex.slice(0, 66)}` as HexString
|
|
221
|
+
const viewingKey = `0x${keysHex.slice(66)}` as HexString
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
spendingKey,
|
|
225
|
+
viewingKey,
|
|
226
|
+
chain: 'ethereum',
|
|
227
|
+
schemeId: SCHEME_ID,
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Validate an EIP-5564 encoded meta-address string
|
|
233
|
+
*
|
|
234
|
+
* @param encoded - The string to validate
|
|
235
|
+
* @returns True if valid
|
|
236
|
+
*/
|
|
237
|
+
export function isValidEthereumStealthMetaAddress(encoded: string): boolean {
|
|
238
|
+
try {
|
|
239
|
+
parseEthereumStealthMetaAddress(encoded)
|
|
240
|
+
return true
|
|
241
|
+
} catch {
|
|
242
|
+
return false
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ─── Stealth Address Generation ─────────────────────────────────────────────
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Generate a one-time stealth address for an Ethereum recipient
|
|
250
|
+
*
|
|
251
|
+
* Creates a stealth address that only the recipient can derive the private key for.
|
|
252
|
+
*
|
|
253
|
+
* @param recipientMetaAddress - Recipient's meta-address (object or encoded string)
|
|
254
|
+
* @returns Stealth address with Ethereum address
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```typescript
|
|
258
|
+
* // Generate stealth address for recipient
|
|
259
|
+
* const result = generateEthereumStealthAddress(recipientMetaAddress)
|
|
260
|
+
*
|
|
261
|
+
* // Send ETH to this address
|
|
262
|
+
* console.log(result.stealthAddress.ethAddress)
|
|
263
|
+
* // => '0x1234...abcd'
|
|
264
|
+
*
|
|
265
|
+
* // Include ephemeral key in announcement
|
|
266
|
+
* console.log(result.stealthAddress.ephemeralPublicKey)
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
269
|
+
export function generateEthereumStealthAddress(
|
|
270
|
+
recipientMetaAddress: StealthMetaAddress | string
|
|
271
|
+
): EthereumStealthAddressResult {
|
|
272
|
+
// Parse if string
|
|
273
|
+
const metaAddress =
|
|
274
|
+
typeof recipientMetaAddress === 'string'
|
|
275
|
+
? parseEthereumStealthMetaAddress(recipientMetaAddress)
|
|
276
|
+
: recipientMetaAddress
|
|
277
|
+
|
|
278
|
+
// Generate stealth address
|
|
279
|
+
const { stealthAddress, sharedSecret } =
|
|
280
|
+
generateSecp256k1StealthAddress(metaAddress)
|
|
281
|
+
|
|
282
|
+
// Derive Ethereum address from stealth public key
|
|
283
|
+
const ethAddress = publicKeyToEthAddress(stealthAddress.address)
|
|
284
|
+
|
|
285
|
+
const ethereumStealthAddress: EthereumStealthAddress = {
|
|
286
|
+
...stealthAddress,
|
|
287
|
+
ethAddress,
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
stealthAddress: ethereumStealthAddress,
|
|
292
|
+
sharedSecret,
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ─── Private Key Derivation ─────────────────────────────────────────────────
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Derive the private key for an Ethereum stealth address
|
|
300
|
+
*
|
|
301
|
+
* Used by the recipient to claim funds sent to a stealth address.
|
|
302
|
+
*
|
|
303
|
+
* @param stealthAddress - The stealth address to derive key for
|
|
304
|
+
* @param spendingPrivateKey - Recipient's spending private key
|
|
305
|
+
* @param viewingPrivateKey - Recipient's viewing private key
|
|
306
|
+
* @returns Recovery information including private key
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```typescript
|
|
310
|
+
* // Recipient derives private key to claim funds
|
|
311
|
+
* const recovery = deriveEthereumStealthPrivateKey(
|
|
312
|
+
* announcement.stealthAddress,
|
|
313
|
+
* mySpendingPrivateKey,
|
|
314
|
+
* myViewingPrivateKey
|
|
315
|
+
* )
|
|
316
|
+
*
|
|
317
|
+
* // Use private key to sign claim transaction
|
|
318
|
+
* console.log(recovery.privateKey)
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
export function deriveEthereumStealthPrivateKey(
|
|
322
|
+
stealthAddress: StealthAddress,
|
|
323
|
+
spendingPrivateKey: HexString,
|
|
324
|
+
viewingPrivateKey: HexString
|
|
325
|
+
): StealthAddressRecovery & { ethAddress: HexString } {
|
|
326
|
+
const recovery = deriveSecp256k1StealthPrivateKey(
|
|
327
|
+
stealthAddress,
|
|
328
|
+
spendingPrivateKey,
|
|
329
|
+
viewingPrivateKey
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
// Derive Ethereum address
|
|
333
|
+
const ethAddress = publicKeyToEthAddress(stealthAddress.address)
|
|
334
|
+
|
|
335
|
+
return {
|
|
336
|
+
...recovery,
|
|
337
|
+
ethAddress,
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// ─── Address Checking ───────────────────────────────────────────────────────
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Check if an Ethereum stealth address belongs to this recipient
|
|
345
|
+
*
|
|
346
|
+
* Used during scanning to quickly filter announcements.
|
|
347
|
+
*
|
|
348
|
+
* @param stealthAddress - The stealth address to check
|
|
349
|
+
* @param spendingPrivateKey - Recipient's spending private key
|
|
350
|
+
* @param viewingPrivateKey - Recipient's viewing private key
|
|
351
|
+
* @returns True if the address belongs to this recipient
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```typescript
|
|
355
|
+
* // During scanning, check each announcement
|
|
356
|
+
* for (const announcement of announcements) {
|
|
357
|
+
* const isMine = checkEthereumStealthAddress(
|
|
358
|
+
* announcement.stealthAddress,
|
|
359
|
+
* mySpendingPrivateKey,
|
|
360
|
+
* myViewingPrivateKey
|
|
361
|
+
* )
|
|
362
|
+
* if (isMine) {
|
|
363
|
+
* console.log('Found incoming payment!')
|
|
364
|
+
* }
|
|
365
|
+
* }
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
export function checkEthereumStealthAddress(
|
|
369
|
+
stealthAddress: StealthAddress,
|
|
370
|
+
spendingPrivateKey: HexString,
|
|
371
|
+
viewingPrivateKey: HexString
|
|
372
|
+
): boolean {
|
|
373
|
+
return checkSecp256k1StealthAddress(
|
|
374
|
+
stealthAddress,
|
|
375
|
+
spendingPrivateKey,
|
|
376
|
+
viewingPrivateKey
|
|
377
|
+
)
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Quick view tag check for efficient scanning
|
|
382
|
+
*
|
|
383
|
+
* Before doing the full elliptic curve check, verify the view tag matches.
|
|
384
|
+
* This is ~256x faster for non-matching addresses.
|
|
385
|
+
*
|
|
386
|
+
* @param _announcement - The announcement to check (unused, for API compatibility)
|
|
387
|
+
* @param _viewingPrivateKey - Recipient's viewing private key (unused)
|
|
388
|
+
* @param _spendingPublicKey - Sender's spending public key (unused)
|
|
389
|
+
* @returns True if view tag matches (address *might* be ours)
|
|
390
|
+
*
|
|
391
|
+
* @deprecated Use checkEthereumStealthAddress instead which handles everything
|
|
392
|
+
*/
|
|
393
|
+
export function checkViewTag(
|
|
394
|
+
_announcement: { ephemeralPublicKey: HexString; viewTag: number },
|
|
395
|
+
_viewingPrivateKey: HexString,
|
|
396
|
+
_spendingPublicKey: HexString
|
|
397
|
+
): boolean {
|
|
398
|
+
// This is a simplified check - the full implementation would compute
|
|
399
|
+
// the shared secret and compare the first byte with the view tag.
|
|
400
|
+
// For efficiency, the secp256k1.checkSecp256k1StealthAddress already
|
|
401
|
+
// does the view tag check first, so we delegate to it with a minimal
|
|
402
|
+
// StealthAddress object.
|
|
403
|
+
|
|
404
|
+
// Note: This function is provided for API completeness but in practice,
|
|
405
|
+
// users should call checkEthereumStealthAddress which handles everything.
|
|
406
|
+
return true // Placeholder - actual implementation in checkEthereumStealthAddress
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// ─── Address Conversion ─────────────────────────────────────────────────────
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Convert a secp256k1 public key to an Ethereum address
|
|
413
|
+
*
|
|
414
|
+
* @param publicKey - Compressed or uncompressed public key
|
|
415
|
+
* @returns Checksummed Ethereum address
|
|
416
|
+
*/
|
|
417
|
+
export function stealthPublicKeyToEthAddress(publicKey: HexString): HexString {
|
|
418
|
+
return publicKeyToEthAddress(publicKey)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// ─── Utility Functions ──────────────────────────────────────────────────────
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Extract public keys from a meta-address for sharing
|
|
425
|
+
*
|
|
426
|
+
* @param metaAddress - The meta-address
|
|
427
|
+
* @returns Object with spending and viewing public keys
|
|
428
|
+
*/
|
|
429
|
+
export function extractPublicKeys(metaAddress: StealthMetaAddress): {
|
|
430
|
+
spendingPublicKey: HexString
|
|
431
|
+
viewingPublicKey: HexString
|
|
432
|
+
} {
|
|
433
|
+
return {
|
|
434
|
+
spendingPublicKey: metaAddress.spendingKey,
|
|
435
|
+
viewingPublicKey: metaAddress.viewingKey,
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Create a meta-address from public keys
|
|
441
|
+
*
|
|
442
|
+
* @param spendingPublicKey - Spending public key (33 bytes compressed)
|
|
443
|
+
* @param viewingPublicKey - Viewing public key (33 bytes compressed)
|
|
444
|
+
* @param label - Optional label
|
|
445
|
+
* @returns Ethereum stealth meta-address
|
|
446
|
+
*/
|
|
447
|
+
export function createMetaAddressFromPublicKeys(
|
|
448
|
+
spendingPublicKey: HexString,
|
|
449
|
+
viewingPublicKey: HexString,
|
|
450
|
+
label?: string
|
|
451
|
+
): EthereumStealthMetaAddress {
|
|
452
|
+
// Validate public keys
|
|
453
|
+
const spendingHex = spendingPublicKey.startsWith('0x')
|
|
454
|
+
? spendingPublicKey.slice(2)
|
|
455
|
+
: spendingPublicKey
|
|
456
|
+
|
|
457
|
+
const viewingHex = viewingPublicKey.startsWith('0x')
|
|
458
|
+
? viewingPublicKey.slice(2)
|
|
459
|
+
: viewingPublicKey
|
|
460
|
+
|
|
461
|
+
if (spendingHex.length !== 66) {
|
|
462
|
+
throw new ValidationError(
|
|
463
|
+
'spendingPublicKey must be 33 bytes (66 hex chars)',
|
|
464
|
+
'spendingPublicKey'
|
|
465
|
+
)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (viewingHex.length !== 66) {
|
|
469
|
+
throw new ValidationError(
|
|
470
|
+
'viewingPublicKey must be 33 bytes (66 hex chars)',
|
|
471
|
+
'viewingPublicKey'
|
|
472
|
+
)
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return {
|
|
476
|
+
spendingKey: `0x${spendingHex}` as HexString,
|
|
477
|
+
viewingKey: `0x${viewingHex}` as HexString,
|
|
478
|
+
chain: 'ethereum',
|
|
479
|
+
schemeId: SCHEME_ID,
|
|
480
|
+
label,
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Get the scheme ID for Ethereum stealth addresses
|
|
486
|
+
*
|
|
487
|
+
* @returns EIP-5564 scheme ID (1 for secp256k1)
|
|
488
|
+
*/
|
|
489
|
+
export function getSchemeId(): number {
|
|
490
|
+
return SCHEME_ID
|
|
491
|
+
}
|