@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,871 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NEAR Function Call Privacy Wrapper
|
|
3
|
+
*
|
|
4
|
+
* Privacy-preserving contract interactions using stealth accounts.
|
|
5
|
+
* Enables private DeFi, NFT, and smart contract interactions while
|
|
6
|
+
* hiding caller identity.
|
|
7
|
+
*
|
|
8
|
+
* @example Private contract call from stealth account
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { buildPrivateFunctionCall } from '@sip-protocol/sdk'
|
|
11
|
+
*
|
|
12
|
+
* const result = buildPrivateFunctionCall({
|
|
13
|
+
* contractId: 'dex.near',
|
|
14
|
+
* methodName: 'swap',
|
|
15
|
+
* args: { token_in: 'usdc.near', amount: '1000000' },
|
|
16
|
+
* deposit: ONE_NEAR,
|
|
17
|
+
* hideDeposit: true,
|
|
18
|
+
* })
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example Private NFT mint
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const result = buildPrivateNFTMint({
|
|
24
|
+
* contractId: 'nft.near',
|
|
25
|
+
* receiverMetaAddress: 'sip:near:0x...',
|
|
26
|
+
* tokenId: 'token-1',
|
|
27
|
+
* metadata: { title: 'My NFT' },
|
|
28
|
+
* })
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @packageDocumentation
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import type { StealthAddress, StealthMetaAddress } from '@sip-protocol/types'
|
|
35
|
+
import { ValidationError } from '../../errors'
|
|
36
|
+
import { isValidAccountId, ONE_YOCTO } from './constants'
|
|
37
|
+
import { generateNEARStealthAddress, parseNEARStealthMetaAddress } from './stealth'
|
|
38
|
+
import { createAnnouncementMemo } from './types'
|
|
39
|
+
import { commitNEAR, type NEARPedersenCommitment } from './commitment'
|
|
40
|
+
import type {
|
|
41
|
+
NEARAction,
|
|
42
|
+
NEARFunctionCallAction,
|
|
43
|
+
NEARAddKeyAction,
|
|
44
|
+
} from './implicit-account'
|
|
45
|
+
|
|
46
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parameters for a private function call
|
|
50
|
+
*/
|
|
51
|
+
export interface PrivateFunctionCallParams {
|
|
52
|
+
/** Contract to call */
|
|
53
|
+
contractId: string
|
|
54
|
+
/** Method name to invoke */
|
|
55
|
+
methodName: string
|
|
56
|
+
/** Method arguments (will be JSON stringified) */
|
|
57
|
+
args?: Record<string, unknown>
|
|
58
|
+
/** NEAR deposit to attach (default: 0) */
|
|
59
|
+
deposit?: bigint
|
|
60
|
+
/** Gas to attach (default: DEFAULT_GAS) */
|
|
61
|
+
gas?: bigint
|
|
62
|
+
/** Hide deposit amount with commitment */
|
|
63
|
+
hideDeposit?: boolean
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Result of building a private function call
|
|
68
|
+
*/
|
|
69
|
+
export interface PrivateFunctionCallResult {
|
|
70
|
+
/** Transaction actions */
|
|
71
|
+
actions: NEARAction[]
|
|
72
|
+
/** Receiver ID (the contract) */
|
|
73
|
+
receiverId: string
|
|
74
|
+
/** Deposit commitment (if hideDeposit is true) */
|
|
75
|
+
depositCommitment?: NEARPedersenCommitment
|
|
76
|
+
/** Gas attached */
|
|
77
|
+
gasAttached: bigint
|
|
78
|
+
/** Deposit attached */
|
|
79
|
+
depositAttached: bigint
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Parameters for a private function call from a stealth account
|
|
84
|
+
*/
|
|
85
|
+
export interface PrivateFunctionCallFromStealthParams extends PrivateFunctionCallParams {
|
|
86
|
+
/** Stealth account ID to call from */
|
|
87
|
+
stealthAccountId: string
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Parameters for building a multi-step private transaction
|
|
92
|
+
*/
|
|
93
|
+
export interface MultiStepPrivateTransactionParams {
|
|
94
|
+
/** Steps to execute in order */
|
|
95
|
+
steps: Array<{
|
|
96
|
+
/** Contract to call */
|
|
97
|
+
contractId: string
|
|
98
|
+
/** Method name */
|
|
99
|
+
methodName: string
|
|
100
|
+
/** Method arguments */
|
|
101
|
+
args?: Record<string, unknown>
|
|
102
|
+
/** Deposit for this step */
|
|
103
|
+
deposit?: bigint
|
|
104
|
+
/** Gas for this step */
|
|
105
|
+
gas?: bigint
|
|
106
|
+
}>
|
|
107
|
+
/** Total gas budget for all steps */
|
|
108
|
+
totalGas?: bigint
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Result of building a multi-step private transaction
|
|
113
|
+
*/
|
|
114
|
+
export interface MultiStepPrivateTransactionResult {
|
|
115
|
+
/** Individual step builds */
|
|
116
|
+
steps: Array<{
|
|
117
|
+
actions: NEARAction[]
|
|
118
|
+
receiverId: string
|
|
119
|
+
deposit: bigint
|
|
120
|
+
gas: bigint
|
|
121
|
+
}>
|
|
122
|
+
/** Total deposit across all steps */
|
|
123
|
+
totalDeposit: bigint
|
|
124
|
+
/** Total gas across all steps */
|
|
125
|
+
totalGas: bigint
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Parameters for function call access key
|
|
130
|
+
*/
|
|
131
|
+
export interface FunctionCallAccessKeyParams {
|
|
132
|
+
/** Public key to add (ed25519:base58 format) */
|
|
133
|
+
publicKey: string
|
|
134
|
+
/** Contract the key can call */
|
|
135
|
+
receiverId: string
|
|
136
|
+
/** Methods the key can call (empty = all methods) */
|
|
137
|
+
methodNames: string[]
|
|
138
|
+
/** Allowance in yoctoNEAR (optional) */
|
|
139
|
+
allowance?: bigint
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Parameters for private NFT mint
|
|
144
|
+
*/
|
|
145
|
+
export interface PrivateNFTMintParams {
|
|
146
|
+
/** NFT contract address */
|
|
147
|
+
contractId: string
|
|
148
|
+
/** Recipient's stealth meta-address */
|
|
149
|
+
receiverMetaAddress: StealthMetaAddress | string
|
|
150
|
+
/** Token ID */
|
|
151
|
+
tokenId: string
|
|
152
|
+
/** Token metadata */
|
|
153
|
+
metadata?: {
|
|
154
|
+
title?: string
|
|
155
|
+
description?: string
|
|
156
|
+
media?: string
|
|
157
|
+
copies?: number
|
|
158
|
+
}
|
|
159
|
+
/** Deposit for storage (default: 0.1 NEAR) */
|
|
160
|
+
deposit?: bigint
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Result of building a private NFT mint
|
|
165
|
+
*/
|
|
166
|
+
export interface PrivateNFTMintResult {
|
|
167
|
+
/** Transaction actions */
|
|
168
|
+
actions: NEARAction[]
|
|
169
|
+
/** NFT contract address */
|
|
170
|
+
receiverId: string
|
|
171
|
+
/** Stealth address receiving the NFT */
|
|
172
|
+
stealthAddress: StealthAddress
|
|
173
|
+
/** NEAR implicit account ID */
|
|
174
|
+
stealthAccountId: string
|
|
175
|
+
/** Announcement memo */
|
|
176
|
+
announcementMemo: string
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Parameters for private DeFi swap
|
|
181
|
+
*/
|
|
182
|
+
export interface PrivateDeFiSwapParams {
|
|
183
|
+
/** DEX contract address */
|
|
184
|
+
dexContract: string
|
|
185
|
+
/** Token to swap from */
|
|
186
|
+
tokenIn: string
|
|
187
|
+
/** Token to swap to */
|
|
188
|
+
tokenOut: string
|
|
189
|
+
/** Amount to swap (in smallest units) */
|
|
190
|
+
amountIn: bigint
|
|
191
|
+
/** Minimum amount to receive */
|
|
192
|
+
minAmountOut: bigint
|
|
193
|
+
/** Recipient's stealth meta-address for output */
|
|
194
|
+
receiverMetaAddress: StealthMetaAddress | string
|
|
195
|
+
/** Slippage tolerance (default: 0.5%) */
|
|
196
|
+
slippageBps?: number
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Result of building a private DeFi swap
|
|
201
|
+
*/
|
|
202
|
+
export interface PrivateDeFiSwapResult {
|
|
203
|
+
/** Transaction actions */
|
|
204
|
+
actions: NEARAction[]
|
|
205
|
+
/** DEX contract address */
|
|
206
|
+
receiverId: string
|
|
207
|
+
/** Stealth address receiving swap output */
|
|
208
|
+
stealthAddress: StealthAddress
|
|
209
|
+
/** NEAR implicit account ID */
|
|
210
|
+
stealthAccountId: string
|
|
211
|
+
/** Announcement memo */
|
|
212
|
+
announcementMemo: string
|
|
213
|
+
/** Expected output amount */
|
|
214
|
+
expectedOutput: bigint
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Default gas for function calls (30 TGas)
|
|
221
|
+
*/
|
|
222
|
+
export const FUNCTION_CALL_DEFAULT_GAS = 30_000_000_000_000n
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Gas for NFT mint operations (50 TGas)
|
|
226
|
+
*/
|
|
227
|
+
export const NFT_MINT_GAS = 50_000_000_000_000n
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Default deposit for NFT storage (0.1 NEAR)
|
|
231
|
+
*/
|
|
232
|
+
export const NFT_STORAGE_DEPOSIT = 100_000_000_000_000_000_000_000n
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Gas for DEX swap operations (100 TGas)
|
|
236
|
+
*/
|
|
237
|
+
export const DEX_SWAP_GAS = 100_000_000_000_000n
|
|
238
|
+
|
|
239
|
+
// ─── Private Function Calls ───────────────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Build a private function call
|
|
243
|
+
*
|
|
244
|
+
* Creates a function call action that can be executed from a stealth account,
|
|
245
|
+
* optionally hiding the deposit amount with a Pedersen commitment.
|
|
246
|
+
*
|
|
247
|
+
* @param params - Function call parameters
|
|
248
|
+
* @returns Function call build
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```typescript
|
|
252
|
+
* const result = buildPrivateFunctionCall({
|
|
253
|
+
* contractId: 'dex.near',
|
|
254
|
+
* methodName: 'swap',
|
|
255
|
+
* args: { token_in: 'usdc.near', amount: '1000000' },
|
|
256
|
+
* deposit: ONE_NEAR,
|
|
257
|
+
* hideDeposit: true,
|
|
258
|
+
* })
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
export function buildPrivateFunctionCall(
|
|
262
|
+
params: PrivateFunctionCallParams
|
|
263
|
+
): PrivateFunctionCallResult {
|
|
264
|
+
const {
|
|
265
|
+
contractId,
|
|
266
|
+
methodName,
|
|
267
|
+
args = {},
|
|
268
|
+
deposit = 0n,
|
|
269
|
+
gas = FUNCTION_CALL_DEFAULT_GAS,
|
|
270
|
+
hideDeposit = false,
|
|
271
|
+
} = params
|
|
272
|
+
|
|
273
|
+
// Validate contract ID
|
|
274
|
+
if (!isValidAccountId(contractId)) {
|
|
275
|
+
throw new ValidationError('Invalid contractId', 'contractId')
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Validate method name
|
|
279
|
+
if (!methodName || methodName.length === 0) {
|
|
280
|
+
throw new ValidationError('methodName is required', 'methodName')
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Validate gas
|
|
284
|
+
if (gas <= 0n) {
|
|
285
|
+
throw new ValidationError('gas must be greater than 0', 'gas')
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Validate deposit
|
|
289
|
+
if (deposit < 0n) {
|
|
290
|
+
throw new ValidationError('deposit cannot be negative', 'deposit')
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Create deposit commitment if requested
|
|
294
|
+
let depositCommitment: NEARPedersenCommitment | undefined
|
|
295
|
+
if (hideDeposit && deposit > 0n) {
|
|
296
|
+
depositCommitment = commitNEAR(deposit)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Build function call args
|
|
300
|
+
const argsString = JSON.stringify(args)
|
|
301
|
+
|
|
302
|
+
// Build function call action
|
|
303
|
+
const actions: NEARAction[] = [
|
|
304
|
+
{
|
|
305
|
+
type: 'FunctionCall',
|
|
306
|
+
params: {
|
|
307
|
+
methodName,
|
|
308
|
+
args: argsString,
|
|
309
|
+
gas,
|
|
310
|
+
deposit,
|
|
311
|
+
} as NEARFunctionCallAction,
|
|
312
|
+
},
|
|
313
|
+
]
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
actions,
|
|
317
|
+
receiverId: contractId,
|
|
318
|
+
depositCommitment,
|
|
319
|
+
gasAttached: gas,
|
|
320
|
+
depositAttached: deposit,
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Build a batch of private function calls
|
|
326
|
+
*
|
|
327
|
+
* Creates multiple function call actions for a single transaction.
|
|
328
|
+
* All calls are to the same contract.
|
|
329
|
+
*
|
|
330
|
+
* @param contractId - Contract to call
|
|
331
|
+
* @param calls - List of method calls
|
|
332
|
+
* @returns Batch function call build
|
|
333
|
+
*/
|
|
334
|
+
export function buildBatchPrivateFunctionCalls(
|
|
335
|
+
contractId: string,
|
|
336
|
+
calls: Array<{
|
|
337
|
+
methodName: string
|
|
338
|
+
args?: Record<string, unknown>
|
|
339
|
+
deposit?: bigint
|
|
340
|
+
gas?: bigint
|
|
341
|
+
}>
|
|
342
|
+
): PrivateFunctionCallResult {
|
|
343
|
+
if (!isValidAccountId(contractId)) {
|
|
344
|
+
throw new ValidationError('Invalid contractId', 'contractId')
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (!calls || calls.length === 0) {
|
|
348
|
+
throw new ValidationError('At least one call is required', 'calls')
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (calls.length > 10) {
|
|
352
|
+
throw new ValidationError('Maximum 10 calls per batch', 'calls')
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const actions: NEARAction[] = []
|
|
356
|
+
let totalDeposit = 0n
|
|
357
|
+
let totalGas = 0n
|
|
358
|
+
|
|
359
|
+
for (const call of calls) {
|
|
360
|
+
const {
|
|
361
|
+
methodName,
|
|
362
|
+
args = {},
|
|
363
|
+
deposit = 0n,
|
|
364
|
+
gas = FUNCTION_CALL_DEFAULT_GAS,
|
|
365
|
+
} = call
|
|
366
|
+
|
|
367
|
+
if (!methodName || methodName.length === 0) {
|
|
368
|
+
throw new ValidationError('methodName is required for each call', 'calls')
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
actions.push({
|
|
372
|
+
type: 'FunctionCall',
|
|
373
|
+
params: {
|
|
374
|
+
methodName,
|
|
375
|
+
args: JSON.stringify(args),
|
|
376
|
+
gas,
|
|
377
|
+
deposit,
|
|
378
|
+
} as NEARFunctionCallAction,
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
totalDeposit += deposit
|
|
382
|
+
totalGas += gas
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
actions,
|
|
387
|
+
receiverId: contractId,
|
|
388
|
+
gasAttached: totalGas,
|
|
389
|
+
depositAttached: totalDeposit,
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Build a multi-step private transaction
|
|
395
|
+
*
|
|
396
|
+
* For transactions that need to call multiple contracts in sequence.
|
|
397
|
+
* Returns separate transaction builds for each step.
|
|
398
|
+
*
|
|
399
|
+
* @param params - Multi-step transaction parameters
|
|
400
|
+
* @returns Multi-step transaction build
|
|
401
|
+
*/
|
|
402
|
+
export function buildMultiStepPrivateTransaction(
|
|
403
|
+
params: MultiStepPrivateTransactionParams
|
|
404
|
+
): MultiStepPrivateTransactionResult {
|
|
405
|
+
const { steps, totalGas } = params
|
|
406
|
+
|
|
407
|
+
if (!steps || steps.length === 0) {
|
|
408
|
+
throw new ValidationError('At least one step is required', 'steps')
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (steps.length > 10) {
|
|
412
|
+
throw new ValidationError('Maximum 10 steps per transaction', 'steps')
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const results: MultiStepPrivateTransactionResult['steps'] = []
|
|
416
|
+
let totalDeposit = 0n
|
|
417
|
+
let calculatedTotalGas = 0n
|
|
418
|
+
|
|
419
|
+
// Calculate gas per step if total is specified
|
|
420
|
+
const gasPerStep = totalGas
|
|
421
|
+
? totalGas / BigInt(steps.length)
|
|
422
|
+
: undefined
|
|
423
|
+
|
|
424
|
+
for (const step of steps) {
|
|
425
|
+
const {
|
|
426
|
+
contractId,
|
|
427
|
+
methodName,
|
|
428
|
+
args = {},
|
|
429
|
+
deposit = 0n,
|
|
430
|
+
gas = gasPerStep ?? FUNCTION_CALL_DEFAULT_GAS,
|
|
431
|
+
} = step
|
|
432
|
+
|
|
433
|
+
if (!isValidAccountId(contractId)) {
|
|
434
|
+
throw new ValidationError(`Invalid contractId: ${contractId}`, 'steps')
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (!methodName || methodName.length === 0) {
|
|
438
|
+
throw new ValidationError('methodName is required for each step', 'steps')
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const actions: NEARAction[] = [
|
|
442
|
+
{
|
|
443
|
+
type: 'FunctionCall',
|
|
444
|
+
params: {
|
|
445
|
+
methodName,
|
|
446
|
+
args: JSON.stringify(args),
|
|
447
|
+
gas,
|
|
448
|
+
deposit,
|
|
449
|
+
} as NEARFunctionCallAction,
|
|
450
|
+
},
|
|
451
|
+
]
|
|
452
|
+
|
|
453
|
+
results.push({
|
|
454
|
+
actions,
|
|
455
|
+
receiverId: contractId,
|
|
456
|
+
deposit,
|
|
457
|
+
gas,
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
totalDeposit += deposit
|
|
461
|
+
calculatedTotalGas += gas
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return {
|
|
465
|
+
steps: results,
|
|
466
|
+
totalDeposit,
|
|
467
|
+
totalGas: calculatedTotalGas,
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// ─── Access Key Management ────────────────────────────────────────────────────
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Build function call access key for a stealth account
|
|
475
|
+
*
|
|
476
|
+
* Allows adding a limited access key to a stealth account that can
|
|
477
|
+
* only call specific methods on a specific contract.
|
|
478
|
+
*
|
|
479
|
+
* @param params - Access key parameters
|
|
480
|
+
* @returns Add key action
|
|
481
|
+
*
|
|
482
|
+
* @example
|
|
483
|
+
* ```typescript
|
|
484
|
+
* const action = buildFunctionCallAccessKey({
|
|
485
|
+
* publicKey: 'ed25519:...',
|
|
486
|
+
* receiverId: 'dex.near',
|
|
487
|
+
* methodNames: ['swap', 'deposit', 'withdraw'],
|
|
488
|
+
* allowance: ONE_NEAR,
|
|
489
|
+
* })
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
export function buildFunctionCallAccessKey(
|
|
493
|
+
params: FunctionCallAccessKeyParams
|
|
494
|
+
): NEARAction {
|
|
495
|
+
const {
|
|
496
|
+
publicKey,
|
|
497
|
+
receiverId,
|
|
498
|
+
methodNames,
|
|
499
|
+
allowance,
|
|
500
|
+
} = params
|
|
501
|
+
|
|
502
|
+
// Validate public key format
|
|
503
|
+
if (!publicKey.startsWith('ed25519:')) {
|
|
504
|
+
throw new ValidationError(
|
|
505
|
+
'publicKey must be in ed25519:base58 format',
|
|
506
|
+
'publicKey'
|
|
507
|
+
)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Validate receiver
|
|
511
|
+
if (!isValidAccountId(receiverId)) {
|
|
512
|
+
throw new ValidationError('Invalid receiverId', 'receiverId')
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
type: 'AddKey',
|
|
517
|
+
params: {
|
|
518
|
+
publicKey,
|
|
519
|
+
accessKey: {
|
|
520
|
+
permission: {
|
|
521
|
+
FunctionCall: {
|
|
522
|
+
allowance,
|
|
523
|
+
receiverId,
|
|
524
|
+
methodNames,
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
} as NEARAddKeyAction,
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// ─── NFT Privacy ──────────────────────────────────────────────────────────────
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Build a private NFT mint
|
|
536
|
+
*
|
|
537
|
+
* Mints an NFT to a stealth address, hiding the recipient's identity.
|
|
538
|
+
*
|
|
539
|
+
* @param params - NFT mint parameters
|
|
540
|
+
* @returns NFT mint build
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* ```typescript
|
|
544
|
+
* const result = buildPrivateNFTMint({
|
|
545
|
+
* contractId: 'nft.near',
|
|
546
|
+
* receiverMetaAddress: 'sip:near:0x...',
|
|
547
|
+
* tokenId: 'token-1',
|
|
548
|
+
* metadata: { title: 'Private NFT' },
|
|
549
|
+
* })
|
|
550
|
+
* ```
|
|
551
|
+
*/
|
|
552
|
+
export function buildPrivateNFTMint(
|
|
553
|
+
params: PrivateNFTMintParams
|
|
554
|
+
): PrivateNFTMintResult {
|
|
555
|
+
const {
|
|
556
|
+
contractId,
|
|
557
|
+
receiverMetaAddress,
|
|
558
|
+
tokenId,
|
|
559
|
+
metadata = {},
|
|
560
|
+
deposit = NFT_STORAGE_DEPOSIT,
|
|
561
|
+
} = params
|
|
562
|
+
|
|
563
|
+
// Validate contract
|
|
564
|
+
if (!isValidAccountId(contractId)) {
|
|
565
|
+
throw new ValidationError('Invalid NFT contractId', 'contractId')
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Parse meta-address if string
|
|
569
|
+
const metaAddr = typeof receiverMetaAddress === 'string'
|
|
570
|
+
? parseNEARStealthMetaAddress(receiverMetaAddress)
|
|
571
|
+
: receiverMetaAddress
|
|
572
|
+
|
|
573
|
+
// Validate chain
|
|
574
|
+
if (metaAddr.chain !== 'near') {
|
|
575
|
+
throw new ValidationError(
|
|
576
|
+
`Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
|
|
577
|
+
'receiverMetaAddress'
|
|
578
|
+
)
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Generate stealth address for receiver
|
|
582
|
+
const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
|
|
583
|
+
|
|
584
|
+
// Create announcement memo
|
|
585
|
+
const announcementMemo = createAnnouncementMemo(
|
|
586
|
+
stealthAddress.ephemeralPublicKey,
|
|
587
|
+
stealthAddress.viewTag
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
// Build NFT mint args (NEP-171 standard)
|
|
591
|
+
const args = {
|
|
592
|
+
token_id: tokenId,
|
|
593
|
+
receiver_id: implicitAccountId,
|
|
594
|
+
token_metadata: {
|
|
595
|
+
title: metadata.title,
|
|
596
|
+
description: metadata.description,
|
|
597
|
+
media: metadata.media,
|
|
598
|
+
copies: metadata.copies,
|
|
599
|
+
},
|
|
600
|
+
memo: announcementMemo,
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Build mint action
|
|
604
|
+
const actions: NEARAction[] = [
|
|
605
|
+
{
|
|
606
|
+
type: 'FunctionCall',
|
|
607
|
+
params: {
|
|
608
|
+
methodName: 'nft_mint',
|
|
609
|
+
args: JSON.stringify(args),
|
|
610
|
+
gas: NFT_MINT_GAS,
|
|
611
|
+
deposit,
|
|
612
|
+
} as NEARFunctionCallAction,
|
|
613
|
+
},
|
|
614
|
+
]
|
|
615
|
+
|
|
616
|
+
return {
|
|
617
|
+
actions,
|
|
618
|
+
receiverId: contractId,
|
|
619
|
+
stealthAddress,
|
|
620
|
+
stealthAccountId: implicitAccountId,
|
|
621
|
+
announcementMemo,
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Build a private NFT transfer
|
|
627
|
+
*
|
|
628
|
+
* Transfers an NFT to a stealth address.
|
|
629
|
+
*
|
|
630
|
+
* @param contractId - NFT contract address
|
|
631
|
+
* @param tokenId - Token ID to transfer
|
|
632
|
+
* @param receiverMetaAddress - Recipient's stealth meta-address
|
|
633
|
+
* @returns NFT transfer build
|
|
634
|
+
*/
|
|
635
|
+
export function buildPrivateNFTTransfer(
|
|
636
|
+
contractId: string,
|
|
637
|
+
tokenId: string,
|
|
638
|
+
receiverMetaAddress: StealthMetaAddress | string
|
|
639
|
+
): PrivateNFTMintResult {
|
|
640
|
+
// Validate contract
|
|
641
|
+
if (!isValidAccountId(contractId)) {
|
|
642
|
+
throw new ValidationError('Invalid NFT contractId', 'contractId')
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Parse meta-address if string
|
|
646
|
+
const metaAddr = typeof receiverMetaAddress === 'string'
|
|
647
|
+
? parseNEARStealthMetaAddress(receiverMetaAddress)
|
|
648
|
+
: receiverMetaAddress
|
|
649
|
+
|
|
650
|
+
// Validate chain
|
|
651
|
+
if (metaAddr.chain !== 'near') {
|
|
652
|
+
throw new ValidationError(
|
|
653
|
+
`Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
|
|
654
|
+
'receiverMetaAddress'
|
|
655
|
+
)
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Generate stealth address for receiver
|
|
659
|
+
const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
|
|
660
|
+
|
|
661
|
+
// Create announcement memo
|
|
662
|
+
const announcementMemo = createAnnouncementMemo(
|
|
663
|
+
stealthAddress.ephemeralPublicKey,
|
|
664
|
+
stealthAddress.viewTag
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
// Build NFT transfer args (NEP-171 standard)
|
|
668
|
+
const args = {
|
|
669
|
+
token_id: tokenId,
|
|
670
|
+
receiver_id: implicitAccountId,
|
|
671
|
+
memo: announcementMemo,
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Build transfer action
|
|
675
|
+
const actions: NEARAction[] = [
|
|
676
|
+
{
|
|
677
|
+
type: 'FunctionCall',
|
|
678
|
+
params: {
|
|
679
|
+
methodName: 'nft_transfer',
|
|
680
|
+
args: JSON.stringify(args),
|
|
681
|
+
gas: NFT_MINT_GAS,
|
|
682
|
+
deposit: ONE_YOCTO, // NEP-171 requires 1 yoctoNEAR
|
|
683
|
+
} as NEARFunctionCallAction,
|
|
684
|
+
},
|
|
685
|
+
]
|
|
686
|
+
|
|
687
|
+
return {
|
|
688
|
+
actions,
|
|
689
|
+
receiverId: contractId,
|
|
690
|
+
stealthAddress,
|
|
691
|
+
stealthAccountId: implicitAccountId,
|
|
692
|
+
announcementMemo,
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// ─── DeFi Privacy ─────────────────────────────────────────────────────────────
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Build a private DeFi swap
|
|
700
|
+
*
|
|
701
|
+
* Executes a token swap with output going to a stealth address.
|
|
702
|
+
*
|
|
703
|
+
* @param params - DeFi swap parameters
|
|
704
|
+
* @returns DeFi swap build
|
|
705
|
+
*
|
|
706
|
+
* @example
|
|
707
|
+
* ```typescript
|
|
708
|
+
* const result = buildPrivateDeFiSwap({
|
|
709
|
+
* dexContract: 'ref-finance.near',
|
|
710
|
+
* tokenIn: 'usdc.near',
|
|
711
|
+
* tokenOut: 'wrap.near',
|
|
712
|
+
* amountIn: 1000_000_000n, // 1000 USDC
|
|
713
|
+
* minAmountOut: 900_000_000_000_000_000_000_000n, // min 0.9 NEAR
|
|
714
|
+
* receiverMetaAddress: 'sip:near:0x...',
|
|
715
|
+
* })
|
|
716
|
+
* ```
|
|
717
|
+
*/
|
|
718
|
+
export function buildPrivateDeFiSwap(
|
|
719
|
+
params: PrivateDeFiSwapParams
|
|
720
|
+
): PrivateDeFiSwapResult {
|
|
721
|
+
const {
|
|
722
|
+
dexContract,
|
|
723
|
+
tokenIn,
|
|
724
|
+
tokenOut,
|
|
725
|
+
amountIn,
|
|
726
|
+
minAmountOut,
|
|
727
|
+
receiverMetaAddress,
|
|
728
|
+
slippageBps = 50, // 0.5% default
|
|
729
|
+
} = params
|
|
730
|
+
|
|
731
|
+
// Validate DEX contract
|
|
732
|
+
if (!isValidAccountId(dexContract)) {
|
|
733
|
+
throw new ValidationError('Invalid dexContract', 'dexContract')
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Validate tokens
|
|
737
|
+
if (!isValidAccountId(tokenIn)) {
|
|
738
|
+
throw new ValidationError('Invalid tokenIn', 'tokenIn')
|
|
739
|
+
}
|
|
740
|
+
if (!isValidAccountId(tokenOut)) {
|
|
741
|
+
throw new ValidationError('Invalid tokenOut', 'tokenOut')
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// Validate amounts
|
|
745
|
+
if (amountIn <= 0n) {
|
|
746
|
+
throw new ValidationError('amountIn must be greater than 0', 'amountIn')
|
|
747
|
+
}
|
|
748
|
+
if (minAmountOut <= 0n) {
|
|
749
|
+
throw new ValidationError('minAmountOut must be greater than 0', 'minAmountOut')
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// Parse meta-address if string
|
|
753
|
+
const metaAddr = typeof receiverMetaAddress === 'string'
|
|
754
|
+
? parseNEARStealthMetaAddress(receiverMetaAddress)
|
|
755
|
+
: receiverMetaAddress
|
|
756
|
+
|
|
757
|
+
// Validate chain
|
|
758
|
+
if (metaAddr.chain !== 'near') {
|
|
759
|
+
throw new ValidationError(
|
|
760
|
+
`Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
|
|
761
|
+
'receiverMetaAddress'
|
|
762
|
+
)
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Generate stealth address for swap output
|
|
766
|
+
const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
|
|
767
|
+
|
|
768
|
+
// Create announcement memo
|
|
769
|
+
const announcementMemo = createAnnouncementMemo(
|
|
770
|
+
stealthAddress.ephemeralPublicKey,
|
|
771
|
+
stealthAddress.viewTag
|
|
772
|
+
)
|
|
773
|
+
|
|
774
|
+
// Calculate expected output with slippage
|
|
775
|
+
const slippageMultiplier = 10000n - BigInt(slippageBps)
|
|
776
|
+
const expectedOutput = (minAmountOut * 10000n) / slippageMultiplier
|
|
777
|
+
|
|
778
|
+
// Build swap message for ft_transfer_call
|
|
779
|
+
const swapMsg = JSON.stringify({
|
|
780
|
+
actions: [
|
|
781
|
+
{
|
|
782
|
+
pool_id: 0, // Would need actual pool ID
|
|
783
|
+
token_in: tokenIn,
|
|
784
|
+
token_out: tokenOut,
|
|
785
|
+
amount_in: amountIn.toString(),
|
|
786
|
+
min_amount_out: minAmountOut.toString(),
|
|
787
|
+
},
|
|
788
|
+
],
|
|
789
|
+
receiver_id: implicitAccountId,
|
|
790
|
+
})
|
|
791
|
+
|
|
792
|
+
// Build ft_transfer_call action (to be sent to tokenIn contract)
|
|
793
|
+
const args = {
|
|
794
|
+
receiver_id: dexContract,
|
|
795
|
+
amount: amountIn.toString(),
|
|
796
|
+
msg: swapMsg,
|
|
797
|
+
memo: announcementMemo,
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const actions: NEARAction[] = [
|
|
801
|
+
{
|
|
802
|
+
type: 'FunctionCall',
|
|
803
|
+
params: {
|
|
804
|
+
methodName: 'ft_transfer_call',
|
|
805
|
+
args: JSON.stringify(args),
|
|
806
|
+
gas: DEX_SWAP_GAS,
|
|
807
|
+
deposit: ONE_YOCTO,
|
|
808
|
+
} as NEARFunctionCallAction,
|
|
809
|
+
},
|
|
810
|
+
]
|
|
811
|
+
|
|
812
|
+
return {
|
|
813
|
+
actions,
|
|
814
|
+
receiverId: tokenIn, // Call goes to token contract
|
|
815
|
+
stealthAddress,
|
|
816
|
+
stealthAccountId: implicitAccountId,
|
|
817
|
+
announcementMemo,
|
|
818
|
+
expectedOutput,
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// ─── Gas Estimation ───────────────────────────────────────────────────────────
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Estimate gas for a function call
|
|
826
|
+
*
|
|
827
|
+
* @param methodName - Method being called
|
|
828
|
+
* @param argsSize - Size of args in bytes
|
|
829
|
+
* @returns Estimated gas in yoctoNEAR
|
|
830
|
+
*/
|
|
831
|
+
export function estimateFunctionCallGas(
|
|
832
|
+
methodName: string,
|
|
833
|
+
argsSize: number = 0
|
|
834
|
+
): bigint {
|
|
835
|
+
// Base gas for function call
|
|
836
|
+
let gas = 5_000_000_000_000n // 5 TGas base
|
|
837
|
+
|
|
838
|
+
// Add gas for args serialization
|
|
839
|
+
gas += BigInt(argsSize) * 1_000_000_000n // 1 GGas per byte
|
|
840
|
+
|
|
841
|
+
// Add method-specific gas estimates
|
|
842
|
+
if (methodName === 'ft_transfer' || methodName === 'ft_transfer_call') {
|
|
843
|
+
gas += 10_000_000_000_000n // +10 TGas
|
|
844
|
+
} else if (methodName === 'nft_mint' || methodName === 'nft_transfer') {
|
|
845
|
+
gas += 20_000_000_000_000n // +20 TGas
|
|
846
|
+
} else if (methodName.includes('swap')) {
|
|
847
|
+
gas += 50_000_000_000_000n // +50 TGas for swaps
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Cap at reasonable maximum
|
|
851
|
+
const maxGas = 300_000_000_000_000n // 300 TGas
|
|
852
|
+
return gas > maxGas ? maxGas : gas
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* Estimate total gas for a multi-step transaction
|
|
857
|
+
*
|
|
858
|
+
* @param steps - Transaction steps
|
|
859
|
+
* @returns Total estimated gas
|
|
860
|
+
*/
|
|
861
|
+
export function estimateMultiStepGas(
|
|
862
|
+
steps: Array<{ methodName: string; argsSize?: number }>
|
|
863
|
+
): bigint {
|
|
864
|
+
let total = 0n
|
|
865
|
+
|
|
866
|
+
for (const step of steps) {
|
|
867
|
+
total += estimateFunctionCallGas(step.methodName, step.argsSize ?? 0)
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
return total
|
|
871
|
+
}
|