@sip-protocol/sdk 0.7.2 → 0.7.4
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/LICENSE +21 -0
- 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 +48874 -18336
- package/dist/browser.mjs +674 -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-YWGJ77A2.mjs +33806 -0
- 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-DXh2IGkz.d.ts +24681 -0
- package/dist/index-DeE1ZzA4.d.mts +24681 -0
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48676 -17318
- package/dist/index.mjs +583 -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 +54 -21
- 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 +276 -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 +201 -0
- 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 +402 -0
- package/src/chains/solana/providers/index.ts +85 -0
- package/src/chains/solana/providers/interface.ts +221 -0
- 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 +790 -0
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +170 -73
- 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 +77 -7
- 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 +37 -0
- package/src/compliance/range-sas.ts +956 -0
- 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 +785 -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 +336 -0
- package/src/privacy-backends/interface.ts +906 -0
- 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-types.ts +278 -0
- package/src/privacy-backends/privacycash.ts +456 -0
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +690 -0
- package/src/privacy-backends/router.ts +626 -0
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +256 -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 +111 -30
- 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/surveillance/algorithms/address-reuse.ts +143 -0
- package/src/surveillance/algorithms/cluster.ts +247 -0
- package/src/surveillance/algorithms/exchange.ts +295 -0
- package/src/surveillance/algorithms/temporal.ts +337 -0
- package/src/surveillance/analyzer.ts +442 -0
- package/src/surveillance/index.ts +64 -0
- package/src/surveillance/scoring.ts +372 -0
- package/src/surveillance/types.ts +264 -0
- 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-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/constants-VOI7BSLK.mjs +0 -27
- 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-xbWjohNq.d.mts +0 -11390
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-Q4NAVBTS.mjs +0 -46
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shielded Transaction Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds properly structured Solana transactions for privacy operations.
|
|
5
|
+
* Handles instruction ordering, compute budget, and versioned transactions.
|
|
6
|
+
*
|
|
7
|
+
* @module chains/solana/transaction-builder
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
Connection,
|
|
12
|
+
PublicKey,
|
|
13
|
+
Transaction,
|
|
14
|
+
TransactionInstruction,
|
|
15
|
+
TransactionMessage,
|
|
16
|
+
VersionedTransaction,
|
|
17
|
+
ComputeBudgetProgram,
|
|
18
|
+
SystemProgram,
|
|
19
|
+
AddressLookupTableAccount,
|
|
20
|
+
type Commitment,
|
|
21
|
+
type Blockhash,
|
|
22
|
+
} from '@solana/web3.js'
|
|
23
|
+
import {
|
|
24
|
+
getAssociatedTokenAddress,
|
|
25
|
+
createAssociatedTokenAccountInstruction,
|
|
26
|
+
createTransferInstruction,
|
|
27
|
+
TOKEN_PROGRAM_ID,
|
|
28
|
+
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
29
|
+
} from '@solana/spl-token'
|
|
30
|
+
import {
|
|
31
|
+
generateEd25519StealthAddress,
|
|
32
|
+
ed25519PublicKeyToSolanaAddress,
|
|
33
|
+
} from '../../stealth'
|
|
34
|
+
import type { StealthMetaAddress } from '@sip-protocol/types'
|
|
35
|
+
import { createAnnouncementMemo } from './types'
|
|
36
|
+
import { MEMO_PROGRAM_ID } from './constants'
|
|
37
|
+
|
|
38
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Default compute unit limit for shielded transactions
|
|
42
|
+
* Higher than standard to accommodate memo + potential ATA creation
|
|
43
|
+
*/
|
|
44
|
+
export const DEFAULT_COMPUTE_UNITS = 200_000
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Default priority fee in micro-lamports per compute unit
|
|
48
|
+
*/
|
|
49
|
+
export const DEFAULT_PRIORITY_FEE = 1_000
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Minimum compute units for a simple transfer
|
|
53
|
+
*/
|
|
54
|
+
export const MIN_COMPUTE_UNITS = 50_000
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Maximum compute units allowed
|
|
58
|
+
*/
|
|
59
|
+
export const MAX_COMPUTE_UNITS = 1_400_000
|
|
60
|
+
|
|
61
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Transaction type enumeration
|
|
65
|
+
*/
|
|
66
|
+
export enum ShieldedTransactionType {
|
|
67
|
+
/** SPL token transfer to stealth address */
|
|
68
|
+
SPL_TRANSFER = 'spl_transfer',
|
|
69
|
+
/** Native SOL transfer to stealth address */
|
|
70
|
+
SOL_TRANSFER = 'sol_transfer',
|
|
71
|
+
/** Claim from stealth address */
|
|
72
|
+
CLAIM = 'claim',
|
|
73
|
+
/** Batch transfer to multiple stealth addresses */
|
|
74
|
+
BATCH_TRANSFER = 'batch_transfer',
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Compute budget configuration
|
|
79
|
+
*/
|
|
80
|
+
export interface ComputeBudgetConfig {
|
|
81
|
+
/** Compute unit limit (default: 200,000) */
|
|
82
|
+
units?: number
|
|
83
|
+
/** Priority fee in micro-lamports per compute unit (default: 1,000) */
|
|
84
|
+
priorityFee?: number
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Transaction builder configuration
|
|
89
|
+
*/
|
|
90
|
+
export interface TransactionBuilderConfig {
|
|
91
|
+
/** Solana RPC connection */
|
|
92
|
+
connection: Connection
|
|
93
|
+
/** Fee payer public key */
|
|
94
|
+
feePayer: PublicKey
|
|
95
|
+
/** Use versioned transactions (default: false for legacy) */
|
|
96
|
+
useVersionedTransaction?: boolean
|
|
97
|
+
/** Compute budget configuration */
|
|
98
|
+
computeBudget?: ComputeBudgetConfig
|
|
99
|
+
/** Address lookup tables for account compression */
|
|
100
|
+
lookupTables?: AddressLookupTableAccount[]
|
|
101
|
+
/** Transaction commitment level */
|
|
102
|
+
commitment?: Commitment
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* SPL transfer instruction parameters
|
|
107
|
+
*/
|
|
108
|
+
export interface SPLTransferInstruction {
|
|
109
|
+
/** Token mint address */
|
|
110
|
+
mint: PublicKey
|
|
111
|
+
/** Source token account */
|
|
112
|
+
sourceAccount: PublicKey
|
|
113
|
+
/** Source account owner */
|
|
114
|
+
owner: PublicKey
|
|
115
|
+
/** Recipient's stealth meta-address */
|
|
116
|
+
recipientMetaAddress: StealthMetaAddress
|
|
117
|
+
/** Amount to transfer */
|
|
118
|
+
amount: bigint
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* SOL transfer instruction parameters
|
|
123
|
+
*/
|
|
124
|
+
export interface SOLTransferInstruction {
|
|
125
|
+
/** Source account (sender) */
|
|
126
|
+
sender: PublicKey
|
|
127
|
+
/** Recipient's stealth meta-address */
|
|
128
|
+
recipientMetaAddress: StealthMetaAddress
|
|
129
|
+
/** Amount in lamports */
|
|
130
|
+
amount: bigint
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Built transaction result
|
|
135
|
+
*/
|
|
136
|
+
export interface BuiltTransaction {
|
|
137
|
+
/** Transaction type */
|
|
138
|
+
type: ShieldedTransactionType
|
|
139
|
+
/** Legacy transaction (if useVersionedTransaction is false) */
|
|
140
|
+
transaction?: Transaction
|
|
141
|
+
/** Versioned transaction (if useVersionedTransaction is true) */
|
|
142
|
+
versionedTransaction?: VersionedTransaction
|
|
143
|
+
/** Stealth address details */
|
|
144
|
+
stealthDetails: Array<{
|
|
145
|
+
stealthAddress: string
|
|
146
|
+
ephemeralPublicKey: string
|
|
147
|
+
viewTag: string
|
|
148
|
+
mint?: string
|
|
149
|
+
amount: bigint
|
|
150
|
+
}>
|
|
151
|
+
/** Recent blockhash used */
|
|
152
|
+
blockhash: Blockhash
|
|
153
|
+
/** Last valid block height */
|
|
154
|
+
lastValidBlockHeight: number
|
|
155
|
+
/** Estimated compute units */
|
|
156
|
+
estimatedComputeUnits: number
|
|
157
|
+
/** Estimated fee in lamports */
|
|
158
|
+
estimatedFee: bigint
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Serialized transaction for external signing
|
|
163
|
+
*/
|
|
164
|
+
export interface SerializedTransaction {
|
|
165
|
+
/** Base64 encoded transaction */
|
|
166
|
+
serialized: string
|
|
167
|
+
/** Transaction type */
|
|
168
|
+
type: ShieldedTransactionType
|
|
169
|
+
/** Stealth details for reference */
|
|
170
|
+
stealthDetails: BuiltTransaction['stealthDetails']
|
|
171
|
+
/** Blockhash */
|
|
172
|
+
blockhash: string
|
|
173
|
+
/** Is versioned transaction */
|
|
174
|
+
isVersioned: boolean
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ─── Transaction Builder Class ────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Shielded Transaction Builder
|
|
181
|
+
*
|
|
182
|
+
* Builds properly structured Solana transactions for privacy operations.
|
|
183
|
+
*
|
|
184
|
+
* @example Legacy transaction
|
|
185
|
+
* ```typescript
|
|
186
|
+
* const builder = new ShieldedTransactionBuilder({
|
|
187
|
+
* connection,
|
|
188
|
+
* feePayer: wallet.publicKey,
|
|
189
|
+
* })
|
|
190
|
+
*
|
|
191
|
+
* const built = await builder.buildSPLTransfer({
|
|
192
|
+
* mint: USDC_MINT,
|
|
193
|
+
* sourceAccount: senderATA,
|
|
194
|
+
* owner: wallet.publicKey,
|
|
195
|
+
* recipientMetaAddress: recipientMeta,
|
|
196
|
+
* amount: 5_000_000n,
|
|
197
|
+
* })
|
|
198
|
+
*
|
|
199
|
+
* const signedTx = await wallet.signTransaction(built.transaction!)
|
|
200
|
+
* ```
|
|
201
|
+
*
|
|
202
|
+
* @example Versioned transaction with priority fees
|
|
203
|
+
* ```typescript
|
|
204
|
+
* const builder = new ShieldedTransactionBuilder({
|
|
205
|
+
* connection,
|
|
206
|
+
* feePayer: wallet.publicKey,
|
|
207
|
+
* useVersionedTransaction: true,
|
|
208
|
+
* computeBudget: { units: 300_000, priorityFee: 5_000 },
|
|
209
|
+
* })
|
|
210
|
+
*
|
|
211
|
+
* const built = await builder.buildSOLTransfer({
|
|
212
|
+
* sender: wallet.publicKey,
|
|
213
|
+
* recipientMetaAddress: recipientMeta,
|
|
214
|
+
* amount: 1_000_000_000n,
|
|
215
|
+
* })
|
|
216
|
+
*
|
|
217
|
+
* const signedTx = await wallet.signTransaction(built.versionedTransaction!)
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
export class ShieldedTransactionBuilder {
|
|
221
|
+
private connection: Connection
|
|
222
|
+
private feePayer: PublicKey
|
|
223
|
+
private useVersioned: boolean
|
|
224
|
+
private computeUnits: number
|
|
225
|
+
private priorityFee: number
|
|
226
|
+
private lookupTables: AddressLookupTableAccount[]
|
|
227
|
+
private commitment: Commitment
|
|
228
|
+
|
|
229
|
+
constructor(config: TransactionBuilderConfig) {
|
|
230
|
+
this.connection = config.connection
|
|
231
|
+
this.feePayer = config.feePayer
|
|
232
|
+
this.useVersioned = config.useVersionedTransaction ?? false
|
|
233
|
+
this.computeUnits = config.computeBudget?.units ?? DEFAULT_COMPUTE_UNITS
|
|
234
|
+
this.priorityFee = config.computeBudget?.priorityFee ?? DEFAULT_PRIORITY_FEE
|
|
235
|
+
this.lookupTables = config.lookupTables ?? []
|
|
236
|
+
this.commitment = config.commitment ?? 'confirmed'
|
|
237
|
+
|
|
238
|
+
// Validate compute units
|
|
239
|
+
if (this.computeUnits < MIN_COMPUTE_UNITS || this.computeUnits > MAX_COMPUTE_UNITS) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
`Compute units must be between ${MIN_COMPUTE_UNITS} and ${MAX_COMPUTE_UNITS}`
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ─── SPL Transfer ─────────────────────────────────────────────────────────────
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Build SPL token transfer to stealth address
|
|
250
|
+
*
|
|
251
|
+
* Creates a transaction with:
|
|
252
|
+
* 1. Compute budget instructions (if priority fee > 0)
|
|
253
|
+
* 2. ATA creation instruction (if needed)
|
|
254
|
+
* 3. SPL transfer instruction
|
|
255
|
+
* 4. Memo with ephemeral key announcement
|
|
256
|
+
*/
|
|
257
|
+
async buildSPLTransfer(params: SPLTransferInstruction): Promise<BuiltTransaction> {
|
|
258
|
+
const { mint, sourceAccount, owner, recipientMetaAddress, amount } = params
|
|
259
|
+
|
|
260
|
+
// Validate chain
|
|
261
|
+
if (recipientMetaAddress.chain !== 'solana') {
|
|
262
|
+
throw new Error(`Invalid chain: expected 'solana', got '${recipientMetaAddress.chain}'`)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Generate stealth address
|
|
266
|
+
const { stealthAddress } = generateEd25519StealthAddress(recipientMetaAddress)
|
|
267
|
+
const stealthAddressBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
|
|
268
|
+
const stealthPubkey = new PublicKey(stealthAddressBase58)
|
|
269
|
+
const ephemeralPubkeyBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.ephemeralPublicKey)
|
|
270
|
+
|
|
271
|
+
// Get stealth ATA
|
|
272
|
+
const stealthATA = await getAssociatedTokenAddress(mint, stealthPubkey, true)
|
|
273
|
+
|
|
274
|
+
// Build instructions
|
|
275
|
+
const instructions: TransactionInstruction[] = []
|
|
276
|
+
|
|
277
|
+
// 1. Compute budget (priority fee)
|
|
278
|
+
if (this.priorityFee > 0) {
|
|
279
|
+
instructions.push(
|
|
280
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: this.computeUnits }),
|
|
281
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.priorityFee })
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// 2. ATA creation (if needed)
|
|
286
|
+
let needsAtaCreation = false
|
|
287
|
+
try {
|
|
288
|
+
const accountInfo = await this.connection.getAccountInfo(stealthATA)
|
|
289
|
+
needsAtaCreation = accountInfo === null
|
|
290
|
+
} catch {
|
|
291
|
+
needsAtaCreation = true
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (needsAtaCreation) {
|
|
295
|
+
instructions.push(
|
|
296
|
+
createAssociatedTokenAccountInstruction(
|
|
297
|
+
this.feePayer,
|
|
298
|
+
stealthATA,
|
|
299
|
+
stealthPubkey,
|
|
300
|
+
mint,
|
|
301
|
+
TOKEN_PROGRAM_ID,
|
|
302
|
+
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
303
|
+
)
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// 3. SPL transfer
|
|
308
|
+
instructions.push(
|
|
309
|
+
createTransferInstruction(sourceAccount, stealthATA, owner, amount)
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
// 4. Announcement memo
|
|
313
|
+
const viewTagHex = stealthAddress.viewTag.toString(16).padStart(2, '0')
|
|
314
|
+
const memoContent = createAnnouncementMemo(
|
|
315
|
+
ephemeralPubkeyBase58,
|
|
316
|
+
viewTagHex,
|
|
317
|
+
stealthAddressBase58
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
instructions.push(
|
|
321
|
+
new TransactionInstruction({
|
|
322
|
+
keys: [],
|
|
323
|
+
programId: new PublicKey(MEMO_PROGRAM_ID),
|
|
324
|
+
data: Buffer.from(memoContent, 'utf-8'),
|
|
325
|
+
})
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
return this.buildTransaction(
|
|
329
|
+
instructions,
|
|
330
|
+
ShieldedTransactionType.SPL_TRANSFER,
|
|
331
|
+
[{
|
|
332
|
+
stealthAddress: stealthAddressBase58,
|
|
333
|
+
ephemeralPublicKey: ephemeralPubkeyBase58,
|
|
334
|
+
viewTag: viewTagHex,
|
|
335
|
+
mint: mint.toBase58(),
|
|
336
|
+
amount,
|
|
337
|
+
}]
|
|
338
|
+
)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// ─── SOL Transfer ─────────────────────────────────────────────────────────────
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Build native SOL transfer to stealth address
|
|
345
|
+
*
|
|
346
|
+
* Creates a transaction with:
|
|
347
|
+
* 1. Compute budget instructions (if priority fee > 0)
|
|
348
|
+
* 2. System program transfer
|
|
349
|
+
* 3. Memo with ephemeral key announcement
|
|
350
|
+
*/
|
|
351
|
+
async buildSOLTransfer(params: SOLTransferInstruction): Promise<BuiltTransaction> {
|
|
352
|
+
const { sender, recipientMetaAddress, amount } = params
|
|
353
|
+
|
|
354
|
+
// Validate chain
|
|
355
|
+
if (recipientMetaAddress.chain !== 'solana') {
|
|
356
|
+
throw new Error(`Invalid chain: expected 'solana', got '${recipientMetaAddress.chain}'`)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Generate stealth address
|
|
360
|
+
const { stealthAddress } = generateEd25519StealthAddress(recipientMetaAddress)
|
|
361
|
+
const stealthAddressBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
|
|
362
|
+
const stealthPubkey = new PublicKey(stealthAddressBase58)
|
|
363
|
+
const ephemeralPubkeyBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.ephemeralPublicKey)
|
|
364
|
+
|
|
365
|
+
// Build instructions
|
|
366
|
+
const instructions: TransactionInstruction[] = []
|
|
367
|
+
|
|
368
|
+
// 1. Compute budget (priority fee)
|
|
369
|
+
if (this.priorityFee > 0) {
|
|
370
|
+
instructions.push(
|
|
371
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: this.computeUnits }),
|
|
372
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.priorityFee })
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// 2. System transfer
|
|
377
|
+
instructions.push(
|
|
378
|
+
SystemProgram.transfer({
|
|
379
|
+
fromPubkey: sender,
|
|
380
|
+
toPubkey: stealthPubkey,
|
|
381
|
+
lamports: amount,
|
|
382
|
+
})
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
// 3. Announcement memo
|
|
386
|
+
const viewTagHex = stealthAddress.viewTag.toString(16).padStart(2, '0')
|
|
387
|
+
const memoContent = createAnnouncementMemo(
|
|
388
|
+
ephemeralPubkeyBase58,
|
|
389
|
+
viewTagHex,
|
|
390
|
+
stealthAddressBase58
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
instructions.push(
|
|
394
|
+
new TransactionInstruction({
|
|
395
|
+
keys: [],
|
|
396
|
+
programId: new PublicKey(MEMO_PROGRAM_ID),
|
|
397
|
+
data: Buffer.from(memoContent, 'utf-8'),
|
|
398
|
+
})
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
return this.buildTransaction(
|
|
402
|
+
instructions,
|
|
403
|
+
ShieldedTransactionType.SOL_TRANSFER,
|
|
404
|
+
[{
|
|
405
|
+
stealthAddress: stealthAddressBase58,
|
|
406
|
+
ephemeralPublicKey: ephemeralPubkeyBase58,
|
|
407
|
+
viewTag: viewTagHex,
|
|
408
|
+
amount,
|
|
409
|
+
}]
|
|
410
|
+
)
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// ─── Batch Transfer ───────────────────────────────────────────────────────────
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Build batch SPL transfer to multiple stealth addresses
|
|
417
|
+
*
|
|
418
|
+
* @param mint - Token mint
|
|
419
|
+
* @param sourceAccount - Source token account
|
|
420
|
+
* @param owner - Source account owner
|
|
421
|
+
* @param transfers - Array of recipient + amount pairs
|
|
422
|
+
*/
|
|
423
|
+
async buildBatchSPLTransfer(
|
|
424
|
+
mint: PublicKey,
|
|
425
|
+
sourceAccount: PublicKey,
|
|
426
|
+
owner: PublicKey,
|
|
427
|
+
transfers: Array<{ recipientMetaAddress: StealthMetaAddress; amount: bigint }>
|
|
428
|
+
): Promise<BuiltTransaction> {
|
|
429
|
+
const instructions: TransactionInstruction[] = []
|
|
430
|
+
const stealthDetails: BuiltTransaction['stealthDetails'] = []
|
|
431
|
+
|
|
432
|
+
// 1. Compute budget (higher for batch)
|
|
433
|
+
const batchComputeUnits = Math.min(
|
|
434
|
+
this.computeUnits * Math.ceil(transfers.length / 2),
|
|
435
|
+
MAX_COMPUTE_UNITS
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
if (this.priorityFee > 0) {
|
|
439
|
+
instructions.push(
|
|
440
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: batchComputeUnits }),
|
|
441
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.priorityFee })
|
|
442
|
+
)
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// 2. Process each transfer
|
|
446
|
+
for (const transfer of transfers) {
|
|
447
|
+
if (transfer.recipientMetaAddress.chain !== 'solana') {
|
|
448
|
+
throw new Error(`Invalid chain: expected 'solana'`)
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Generate stealth address
|
|
452
|
+
const { stealthAddress } = generateEd25519StealthAddress(transfer.recipientMetaAddress)
|
|
453
|
+
const stealthAddressBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
|
|
454
|
+
const stealthPubkey = new PublicKey(stealthAddressBase58)
|
|
455
|
+
const ephemeralPubkeyBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.ephemeralPublicKey)
|
|
456
|
+
|
|
457
|
+
// Get/create ATA
|
|
458
|
+
const stealthATA = await getAssociatedTokenAddress(mint, stealthPubkey, true)
|
|
459
|
+
|
|
460
|
+
try {
|
|
461
|
+
const accountInfo = await this.connection.getAccountInfo(stealthATA)
|
|
462
|
+
if (accountInfo === null) {
|
|
463
|
+
instructions.push(
|
|
464
|
+
createAssociatedTokenAccountInstruction(
|
|
465
|
+
this.feePayer,
|
|
466
|
+
stealthATA,
|
|
467
|
+
stealthPubkey,
|
|
468
|
+
mint,
|
|
469
|
+
TOKEN_PROGRAM_ID,
|
|
470
|
+
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
471
|
+
)
|
|
472
|
+
)
|
|
473
|
+
}
|
|
474
|
+
} catch {
|
|
475
|
+
instructions.push(
|
|
476
|
+
createAssociatedTokenAccountInstruction(
|
|
477
|
+
this.feePayer,
|
|
478
|
+
stealthATA,
|
|
479
|
+
stealthPubkey,
|
|
480
|
+
mint,
|
|
481
|
+
TOKEN_PROGRAM_ID,
|
|
482
|
+
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
483
|
+
)
|
|
484
|
+
)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Transfer
|
|
488
|
+
instructions.push(
|
|
489
|
+
createTransferInstruction(sourceAccount, stealthATA, owner, transfer.amount)
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
// Announcement
|
|
493
|
+
const viewTagHex = stealthAddress.viewTag.toString(16).padStart(2, '0')
|
|
494
|
+
const memoContent = createAnnouncementMemo(
|
|
495
|
+
ephemeralPubkeyBase58,
|
|
496
|
+
viewTagHex,
|
|
497
|
+
stealthAddressBase58
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
instructions.push(
|
|
501
|
+
new TransactionInstruction({
|
|
502
|
+
keys: [],
|
|
503
|
+
programId: new PublicKey(MEMO_PROGRAM_ID),
|
|
504
|
+
data: Buffer.from(memoContent, 'utf-8'),
|
|
505
|
+
})
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
stealthDetails.push({
|
|
509
|
+
stealthAddress: stealthAddressBase58,
|
|
510
|
+
ephemeralPublicKey: ephemeralPubkeyBase58,
|
|
511
|
+
viewTag: viewTagHex,
|
|
512
|
+
mint: mint.toBase58(),
|
|
513
|
+
amount: transfer.amount,
|
|
514
|
+
})
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return this.buildTransaction(
|
|
518
|
+
instructions,
|
|
519
|
+
ShieldedTransactionType.BATCH_TRANSFER,
|
|
520
|
+
stealthDetails,
|
|
521
|
+
batchComputeUnits
|
|
522
|
+
)
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// ─── Core Builder ─────────────────────────────────────────────────────────────
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Build transaction from instructions
|
|
529
|
+
*/
|
|
530
|
+
private async buildTransaction(
|
|
531
|
+
instructions: TransactionInstruction[],
|
|
532
|
+
type: ShieldedTransactionType,
|
|
533
|
+
stealthDetails: BuiltTransaction['stealthDetails'],
|
|
534
|
+
computeUnits?: number
|
|
535
|
+
): Promise<BuiltTransaction> {
|
|
536
|
+
const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(
|
|
537
|
+
this.commitment
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
const effectiveComputeUnits = computeUnits ?? this.computeUnits
|
|
541
|
+
|
|
542
|
+
// Calculate estimated fee
|
|
543
|
+
const baseFee = 5000n // Base transaction fee
|
|
544
|
+
const priorityFee = BigInt(Math.ceil((effectiveComputeUnits * this.priorityFee) / 1_000_000))
|
|
545
|
+
const estimatedFee = baseFee + priorityFee
|
|
546
|
+
|
|
547
|
+
if (this.useVersioned) {
|
|
548
|
+
// Build versioned transaction
|
|
549
|
+
const messageV0 = new TransactionMessage({
|
|
550
|
+
payerKey: this.feePayer,
|
|
551
|
+
recentBlockhash: blockhash,
|
|
552
|
+
instructions,
|
|
553
|
+
}).compileToV0Message(this.lookupTables.length > 0 ? this.lookupTables : undefined)
|
|
554
|
+
|
|
555
|
+
const versionedTransaction = new VersionedTransaction(messageV0)
|
|
556
|
+
|
|
557
|
+
return {
|
|
558
|
+
type,
|
|
559
|
+
versionedTransaction,
|
|
560
|
+
stealthDetails,
|
|
561
|
+
blockhash,
|
|
562
|
+
lastValidBlockHeight,
|
|
563
|
+
estimatedComputeUnits: effectiveComputeUnits,
|
|
564
|
+
estimatedFee,
|
|
565
|
+
}
|
|
566
|
+
} else {
|
|
567
|
+
// Build legacy transaction
|
|
568
|
+
const transaction = new Transaction()
|
|
569
|
+
transaction.recentBlockhash = blockhash
|
|
570
|
+
transaction.lastValidBlockHeight = lastValidBlockHeight
|
|
571
|
+
transaction.feePayer = this.feePayer
|
|
572
|
+
instructions.forEach((ix) => transaction.add(ix))
|
|
573
|
+
|
|
574
|
+
return {
|
|
575
|
+
type,
|
|
576
|
+
transaction,
|
|
577
|
+
stealthDetails,
|
|
578
|
+
blockhash,
|
|
579
|
+
lastValidBlockHeight,
|
|
580
|
+
estimatedComputeUnits: effectiveComputeUnits,
|
|
581
|
+
estimatedFee,
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// ─── Serialization ────────────────────────────────────────────────────────────
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Serialize transaction for external signing
|
|
590
|
+
*
|
|
591
|
+
* Useful for wallets that require base64 serialized transactions.
|
|
592
|
+
*/
|
|
593
|
+
serializeForSigning(built: BuiltTransaction): SerializedTransaction {
|
|
594
|
+
let serialized: string
|
|
595
|
+
|
|
596
|
+
if (built.versionedTransaction) {
|
|
597
|
+
serialized = Buffer.from(built.versionedTransaction.serialize()).toString('base64')
|
|
598
|
+
} else if (built.transaction) {
|
|
599
|
+
serialized = built.transaction
|
|
600
|
+
.serialize({ requireAllSignatures: false, verifySignatures: false })
|
|
601
|
+
.toString('base64')
|
|
602
|
+
} else {
|
|
603
|
+
throw new Error('No transaction to serialize')
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return {
|
|
607
|
+
serialized,
|
|
608
|
+
type: built.type,
|
|
609
|
+
stealthDetails: built.stealthDetails,
|
|
610
|
+
blockhash: built.blockhash,
|
|
611
|
+
isVersioned: !!built.versionedTransaction,
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Deserialize a signed transaction
|
|
617
|
+
*/
|
|
618
|
+
deserializeSignedTransaction(
|
|
619
|
+
serialized: string,
|
|
620
|
+
isVersioned: boolean
|
|
621
|
+
): Transaction | VersionedTransaction {
|
|
622
|
+
const buffer = Buffer.from(serialized, 'base64')
|
|
623
|
+
|
|
624
|
+
if (isVersioned) {
|
|
625
|
+
return VersionedTransaction.deserialize(buffer)
|
|
626
|
+
} else {
|
|
627
|
+
return Transaction.from(buffer)
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// ─── Configuration ────────────────────────────────────────────────────────────
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Update compute budget configuration
|
|
635
|
+
*/
|
|
636
|
+
setComputeBudget(config: ComputeBudgetConfig): void {
|
|
637
|
+
if (config.units !== undefined) {
|
|
638
|
+
if (config.units < MIN_COMPUTE_UNITS || config.units > MAX_COMPUTE_UNITS) {
|
|
639
|
+
throw new Error(
|
|
640
|
+
`Compute units must be between ${MIN_COMPUTE_UNITS} and ${MAX_COMPUTE_UNITS}`
|
|
641
|
+
)
|
|
642
|
+
}
|
|
643
|
+
this.computeUnits = config.units
|
|
644
|
+
}
|
|
645
|
+
if (config.priorityFee !== undefined) {
|
|
646
|
+
this.priorityFee = config.priorityFee
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Set lookup tables for account compression
|
|
652
|
+
*/
|
|
653
|
+
setLookupTables(tables: AddressLookupTableAccount[]): void {
|
|
654
|
+
this.lookupTables = tables
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Enable or disable versioned transactions
|
|
659
|
+
*/
|
|
660
|
+
setVersionedTransactions(enabled: boolean): void {
|
|
661
|
+
this.useVersioned = enabled
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Get current configuration
|
|
666
|
+
*/
|
|
667
|
+
getConfig(): {
|
|
668
|
+
computeUnits: number
|
|
669
|
+
priorityFee: number
|
|
670
|
+
useVersioned: boolean
|
|
671
|
+
lookupTablesCount: number
|
|
672
|
+
} {
|
|
673
|
+
return {
|
|
674
|
+
computeUnits: this.computeUnits,
|
|
675
|
+
priorityFee: this.priorityFee,
|
|
676
|
+
useVersioned: this.useVersioned,
|
|
677
|
+
lookupTablesCount: this.lookupTables.length,
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// ─── Factory Function ─────────────────────────────────────────────────────────
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Create a shielded transaction builder
|
|
686
|
+
*
|
|
687
|
+
* @example
|
|
688
|
+
* ```typescript
|
|
689
|
+
* const builder = createTransactionBuilder({
|
|
690
|
+
* connection,
|
|
691
|
+
* feePayer: wallet.publicKey,
|
|
692
|
+
* computeBudget: { priorityFee: 5000 },
|
|
693
|
+
* })
|
|
694
|
+
* ```
|
|
695
|
+
*/
|
|
696
|
+
export function createTransactionBuilder(
|
|
697
|
+
config: TransactionBuilderConfig
|
|
698
|
+
): ShieldedTransactionBuilder {
|
|
699
|
+
return new ShieldedTransactionBuilder(config)
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// ─── Utilities ────────────────────────────────────────────────────────────────
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Estimate compute units for a transaction
|
|
706
|
+
*
|
|
707
|
+
* @param instructions - Transaction instructions
|
|
708
|
+
* @returns Estimated compute units
|
|
709
|
+
*/
|
|
710
|
+
export function estimateComputeUnits(instructions: TransactionInstruction[]): number {
|
|
711
|
+
// Base compute per instruction
|
|
712
|
+
let units = 5000 * instructions.length
|
|
713
|
+
|
|
714
|
+
// Additional compute for specific programs
|
|
715
|
+
for (const ix of instructions) {
|
|
716
|
+
const programId = ix.programId.toBase58()
|
|
717
|
+
|
|
718
|
+
if (programId === TOKEN_PROGRAM_ID.toBase58()) {
|
|
719
|
+
units += 10000 // Token transfer
|
|
720
|
+
} else if (programId === ASSOCIATED_TOKEN_PROGRAM_ID.toBase58()) {
|
|
721
|
+
units += 30000 // ATA creation
|
|
722
|
+
} else if (programId === MEMO_PROGRAM_ID) {
|
|
723
|
+
units += 2000 // Memo
|
|
724
|
+
} else if (programId === SystemProgram.programId.toBase58()) {
|
|
725
|
+
units += 3000 // System transfer
|
|
726
|
+
} else if (programId === ComputeBudgetProgram.programId.toBase58()) {
|
|
727
|
+
units += 500 // Compute budget
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
return Math.min(units, MAX_COMPUTE_UNITS)
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Calculate priority fee from desired priority
|
|
736
|
+
*
|
|
737
|
+
* @param priority - Priority level (low, medium, high, urgent)
|
|
738
|
+
* @returns Priority fee in micro-lamports
|
|
739
|
+
*/
|
|
740
|
+
export function calculatePriorityFee(
|
|
741
|
+
priority: 'low' | 'medium' | 'high' | 'urgent'
|
|
742
|
+
): number {
|
|
743
|
+
switch (priority) {
|
|
744
|
+
case 'low':
|
|
745
|
+
return 100
|
|
746
|
+
case 'medium':
|
|
747
|
+
return 1_000
|
|
748
|
+
case 'high':
|
|
749
|
+
return 10_000
|
|
750
|
+
case 'urgent':
|
|
751
|
+
return 100_000
|
|
752
|
+
default:
|
|
753
|
+
return 1_000
|
|
754
|
+
}
|
|
755
|
+
}
|