@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,775 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NEAR NEP-141 Token Privacy Support
|
|
3
|
+
*
|
|
4
|
+
* Extends basic token transfer functionality with:
|
|
5
|
+
* - Amount commitments for hidden transfer values
|
|
6
|
+
* - ft_transfer_call support for DeFi interactions
|
|
7
|
+
* - Batch token transfers with privacy
|
|
8
|
+
* - Token metadata fetching for UI display
|
|
9
|
+
*
|
|
10
|
+
* @example Privacy-wrapped token transfer with commitment
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { buildPrivateTokenTransferWithCommitment } from '@sip-protocol/sdk'
|
|
13
|
+
*
|
|
14
|
+
* const result = buildPrivateTokenTransferWithCommitment({
|
|
15
|
+
* recipientMetaAddress: 'sip:near:0x...:0x...',
|
|
16
|
+
* tokenContract: 'usdc.near',
|
|
17
|
+
* amount: 100_000_000n, // 100 USDC
|
|
18
|
+
* decimals: 6,
|
|
19
|
+
* hideAmount: true,
|
|
20
|
+
* })
|
|
21
|
+
*
|
|
22
|
+
* // result.commitment contains the hidden amount
|
|
23
|
+
* // result.transfer contains the transaction actions
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example ft_transfer_call for DeFi
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { buildPrivateTokenTransferCall } from '@sip-protocol/sdk'
|
|
29
|
+
*
|
|
30
|
+
* const result = buildPrivateTokenTransferCall({
|
|
31
|
+
* recipientMetaAddress: 'sip:near:0x...:0x...',
|
|
32
|
+
* tokenContract: 'usdc.near',
|
|
33
|
+
* amount: 100_000_000n,
|
|
34
|
+
* msg: JSON.stringify({ action: 'deposit' }),
|
|
35
|
+
* })
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @packageDocumentation
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import type { HexString, StealthAddress, StealthMetaAddress } from '@sip-protocol/types'
|
|
42
|
+
import { ValidationError } from '../../errors'
|
|
43
|
+
import { isValidAccountId, DEFAULT_GAS, ONE_YOCTO, STORAGE_DEPOSIT_DEFAULT } from './constants'
|
|
44
|
+
import { generateNEARStealthAddress, parseNEARStealthMetaAddress } from './stealth'
|
|
45
|
+
import { createAnnouncementMemo } from './types'
|
|
46
|
+
import { commitNEP141Token, type NEP141TokenCommitment } from './commitment'
|
|
47
|
+
import type { NEARAction, NEARFunctionCallAction, NEARPrivateTransferBuild } from './implicit-account'
|
|
48
|
+
|
|
49
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Parameters for a privacy-wrapped token transfer with commitment
|
|
53
|
+
*/
|
|
54
|
+
export interface PrivateTokenTransferWithCommitmentParams {
|
|
55
|
+
/** Recipient's stealth meta-address */
|
|
56
|
+
recipientMetaAddress: StealthMetaAddress | string
|
|
57
|
+
/** NEP-141 token contract address */
|
|
58
|
+
tokenContract: string
|
|
59
|
+
/** Amount in token's smallest units */
|
|
60
|
+
amount: bigint
|
|
61
|
+
/** Token decimals (required for commitment) */
|
|
62
|
+
decimals: number
|
|
63
|
+
/** Whether to create a Pedersen commitment for the amount (default: true) */
|
|
64
|
+
hideAmount?: boolean
|
|
65
|
+
/** Optional memo for the transfer */
|
|
66
|
+
memo?: string
|
|
67
|
+
/** Optional pre-generated blinding factor */
|
|
68
|
+
blinding?: Uint8Array
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Result of building a privacy-wrapped token transfer with commitment
|
|
73
|
+
*/
|
|
74
|
+
export interface PrivateTokenTransferWithCommitmentResult {
|
|
75
|
+
/** The transfer build (actions, stealth address, etc.) */
|
|
76
|
+
transfer: NEARPrivateTransferBuild
|
|
77
|
+
/** Amount commitment (if hideAmount is true) */
|
|
78
|
+
commitment?: NEP141TokenCommitment
|
|
79
|
+
/** The stealth address */
|
|
80
|
+
stealthAddress: StealthAddress
|
|
81
|
+
/** NEAR implicit account ID */
|
|
82
|
+
stealthAccountId: string
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Parameters for ft_transfer_call with privacy
|
|
87
|
+
*/
|
|
88
|
+
export interface PrivateTokenTransferCallParams {
|
|
89
|
+
/** Recipient's stealth meta-address */
|
|
90
|
+
recipientMetaAddress: StealthMetaAddress | string
|
|
91
|
+
/** NEP-141 token contract address */
|
|
92
|
+
tokenContract: string
|
|
93
|
+
/** Amount in token's smallest units */
|
|
94
|
+
amount: bigint
|
|
95
|
+
/** Message to pass to the receiver contract */
|
|
96
|
+
msg: string
|
|
97
|
+
/** Optional memo for the transfer */
|
|
98
|
+
memo?: string
|
|
99
|
+
/** Gas for the receiver callback (default: 30 TGas) */
|
|
100
|
+
receiverGas?: bigint
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Result of building a ft_transfer_call with privacy
|
|
105
|
+
*/
|
|
106
|
+
export interface PrivateTokenTransferCallResult {
|
|
107
|
+
/** Transaction actions */
|
|
108
|
+
actions: NEARAction[]
|
|
109
|
+
/** Receiver ID (the token contract) */
|
|
110
|
+
receiverId: string
|
|
111
|
+
/** The stealth address */
|
|
112
|
+
stealthAddress: StealthAddress
|
|
113
|
+
/** NEAR implicit account ID */
|
|
114
|
+
stealthAccountId: string
|
|
115
|
+
/** Announcement memo */
|
|
116
|
+
announcementMemo: string
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Parameters for batch token transfer
|
|
121
|
+
*/
|
|
122
|
+
export interface BatchTokenTransferParams {
|
|
123
|
+
/** Token contract for all transfers */
|
|
124
|
+
tokenContract: string
|
|
125
|
+
/** List of transfers to execute */
|
|
126
|
+
transfers: Array<{
|
|
127
|
+
/** Recipient's stealth meta-address */
|
|
128
|
+
recipientMetaAddress: StealthMetaAddress | string
|
|
129
|
+
/** Amount in token's smallest units */
|
|
130
|
+
amount: bigint
|
|
131
|
+
}>
|
|
132
|
+
/** Token decimals (for commitments) */
|
|
133
|
+
decimals?: number
|
|
134
|
+
/** Create commitments for amounts */
|
|
135
|
+
hideAmounts?: boolean
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Result of building batch token transfers
|
|
140
|
+
*/
|
|
141
|
+
export interface BatchTokenTransferResult {
|
|
142
|
+
/** Individual transfer results */
|
|
143
|
+
transfers: Array<{
|
|
144
|
+
stealthAddress: StealthAddress
|
|
145
|
+
stealthAccountId: string
|
|
146
|
+
announcementMemo: string
|
|
147
|
+
amount: bigint
|
|
148
|
+
commitment?: NEP141TokenCommitment
|
|
149
|
+
}>
|
|
150
|
+
/** Combined actions for all transfers */
|
|
151
|
+
actions: NEARAction[]
|
|
152
|
+
/** Receiver ID (the token contract) */
|
|
153
|
+
receiverId: string
|
|
154
|
+
/** Total amount being transferred */
|
|
155
|
+
totalAmount: bigint
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* NEP-141 token metadata
|
|
160
|
+
*/
|
|
161
|
+
export interface NEP141TokenMetadata {
|
|
162
|
+
/** Token specification (e.g., "ft-1.0.0") */
|
|
163
|
+
spec: string
|
|
164
|
+
/** Token name */
|
|
165
|
+
name: string
|
|
166
|
+
/** Token symbol */
|
|
167
|
+
symbol: string
|
|
168
|
+
/** Token icon (data URI or URL) */
|
|
169
|
+
icon?: string
|
|
170
|
+
/** Reference URL for additional info */
|
|
171
|
+
reference?: string
|
|
172
|
+
/** SHA256 hash of reference content */
|
|
173
|
+
referenceHash?: string
|
|
174
|
+
/** Number of decimals */
|
|
175
|
+
decimals: number
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Token balance with metadata
|
|
180
|
+
*/
|
|
181
|
+
export interface TokenBalanceInfo {
|
|
182
|
+
/** Balance in smallest units */
|
|
183
|
+
balance: bigint
|
|
184
|
+
/** Token metadata */
|
|
185
|
+
metadata?: NEP141TokenMetadata
|
|
186
|
+
/** Storage deposit status */
|
|
187
|
+
hasStorageDeposit: boolean
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Storage deposit info
|
|
192
|
+
*/
|
|
193
|
+
export interface StorageDepositInfo {
|
|
194
|
+
/** Total storage balance */
|
|
195
|
+
total: bigint
|
|
196
|
+
/** Available storage balance */
|
|
197
|
+
available: bigint
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Default gas for ft_transfer_call receiver callback
|
|
204
|
+
*/
|
|
205
|
+
export const FT_TRANSFER_CALL_GAS = 30_000_000_000_000n // 30 TGas
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Gas for ft_transfer_call itself
|
|
209
|
+
*/
|
|
210
|
+
export const FT_TRANSFER_CALL_TOTAL_GAS = 100_000_000_000_000n // 100 TGas
|
|
211
|
+
|
|
212
|
+
// ─── Privacy-Wrapped Token Transfers ──────────────────────────────────────────
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Build a privacy-wrapped NEP-141 token transfer with optional amount commitment
|
|
216
|
+
*
|
|
217
|
+
* Creates a Pedersen commitment to the amount, allowing the recipient to
|
|
218
|
+
* verify the amount while keeping it hidden from observers.
|
|
219
|
+
*
|
|
220
|
+
* @param params - Transfer parameters
|
|
221
|
+
* @returns Transfer build with optional commitment
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* const result = buildPrivateTokenTransferWithCommitment({
|
|
226
|
+
* recipientMetaAddress: 'sip:near:0x...:0x...',
|
|
227
|
+
* tokenContract: 'usdc.near',
|
|
228
|
+
* amount: 100_000_000n, // 100 USDC
|
|
229
|
+
* decimals: 6,
|
|
230
|
+
* hideAmount: true,
|
|
231
|
+
* })
|
|
232
|
+
*
|
|
233
|
+
* // Share commitment with recipient off-chain
|
|
234
|
+
* // They can verify with the blinding factor
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
export function buildPrivateTokenTransferWithCommitment(
|
|
238
|
+
params: PrivateTokenTransferWithCommitmentParams
|
|
239
|
+
): PrivateTokenTransferWithCommitmentResult {
|
|
240
|
+
const {
|
|
241
|
+
recipientMetaAddress,
|
|
242
|
+
tokenContract,
|
|
243
|
+
amount,
|
|
244
|
+
decimals,
|
|
245
|
+
hideAmount = true,
|
|
246
|
+
memo,
|
|
247
|
+
blinding,
|
|
248
|
+
} = params
|
|
249
|
+
|
|
250
|
+
// Parse meta-address if string
|
|
251
|
+
const metaAddr = typeof recipientMetaAddress === 'string'
|
|
252
|
+
? parseNEARStealthMetaAddress(recipientMetaAddress)
|
|
253
|
+
: recipientMetaAddress
|
|
254
|
+
|
|
255
|
+
// Validate chain
|
|
256
|
+
if (metaAddr.chain !== 'near') {
|
|
257
|
+
throw new ValidationError(
|
|
258
|
+
`Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
|
|
259
|
+
'recipientMetaAddress'
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Validate token contract
|
|
264
|
+
if (!isValidAccountId(tokenContract)) {
|
|
265
|
+
throw new ValidationError('Invalid token contract account ID', 'tokenContract')
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Validate amount
|
|
269
|
+
if (amount <= 0n) {
|
|
270
|
+
throw new ValidationError('amount must be greater than 0', 'amount')
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Generate stealth address
|
|
274
|
+
const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
|
|
275
|
+
|
|
276
|
+
// Create announcement memo
|
|
277
|
+
const announcementMemo = createAnnouncementMemo(
|
|
278
|
+
stealthAddress.ephemeralPublicKey,
|
|
279
|
+
stealthAddress.viewTag
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
// Create amount commitment if requested
|
|
283
|
+
let commitment: NEP141TokenCommitment | undefined
|
|
284
|
+
if (hideAmount) {
|
|
285
|
+
commitment = commitNEP141Token(amount, tokenContract, decimals, blinding)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Build ft_transfer args with commitment hash in memo
|
|
289
|
+
const transferMemo = commitment
|
|
290
|
+
? `${announcementMemo}|c:${commitment.commitment.slice(2, 18)}` // Include commitment prefix
|
|
291
|
+
: announcementMemo
|
|
292
|
+
|
|
293
|
+
const fullMemo = memo ? `${transferMemo}|${memo}` : transferMemo
|
|
294
|
+
const args = JSON.stringify({
|
|
295
|
+
receiver_id: implicitAccountId,
|
|
296
|
+
amount: amount.toString(),
|
|
297
|
+
memo: fullMemo,
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
// Build function call action
|
|
301
|
+
const actions: NEARAction[] = [
|
|
302
|
+
{
|
|
303
|
+
type: 'FunctionCall',
|
|
304
|
+
params: {
|
|
305
|
+
methodName: 'ft_transfer',
|
|
306
|
+
args,
|
|
307
|
+
gas: DEFAULT_GAS,
|
|
308
|
+
deposit: ONE_YOCTO,
|
|
309
|
+
} as NEARFunctionCallAction,
|
|
310
|
+
},
|
|
311
|
+
]
|
|
312
|
+
|
|
313
|
+
const transfer: NEARPrivateTransferBuild = {
|
|
314
|
+
stealthAddress,
|
|
315
|
+
stealthAccountId: implicitAccountId,
|
|
316
|
+
announcementMemo,
|
|
317
|
+
actions,
|
|
318
|
+
receiverId: tokenContract,
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
transfer,
|
|
323
|
+
commitment,
|
|
324
|
+
stealthAddress,
|
|
325
|
+
stealthAccountId: implicitAccountId,
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Build a privacy-wrapped ft_transfer_call for DeFi interactions
|
|
331
|
+
*
|
|
332
|
+
* ft_transfer_call sends tokens and triggers a callback on the receiver,
|
|
333
|
+
* enabling composable DeFi operations with privacy.
|
|
334
|
+
*
|
|
335
|
+
* @param params - Transfer call parameters
|
|
336
|
+
* @returns Transfer call build
|
|
337
|
+
*
|
|
338
|
+
* @example Deposit to a DEX with privacy
|
|
339
|
+
* ```typescript
|
|
340
|
+
* const result = buildPrivateTokenTransferCall({
|
|
341
|
+
* recipientMetaAddress: 'sip:near:0x...:0x...',
|
|
342
|
+
* tokenContract: 'usdc.near',
|
|
343
|
+
* amount: 100_000_000n,
|
|
344
|
+
* msg: JSON.stringify({
|
|
345
|
+
* action: 'swap',
|
|
346
|
+
* output_token: 'wrap.near',
|
|
347
|
+
* min_output: '1000000000000000000000000',
|
|
348
|
+
* }),
|
|
349
|
+
* })
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
export function buildPrivateTokenTransferCall(
|
|
353
|
+
params: PrivateTokenTransferCallParams
|
|
354
|
+
): PrivateTokenTransferCallResult {
|
|
355
|
+
const {
|
|
356
|
+
recipientMetaAddress,
|
|
357
|
+
tokenContract,
|
|
358
|
+
amount,
|
|
359
|
+
msg,
|
|
360
|
+
memo,
|
|
361
|
+
receiverGas = FT_TRANSFER_CALL_GAS,
|
|
362
|
+
} = params
|
|
363
|
+
|
|
364
|
+
// Parse meta-address if string
|
|
365
|
+
const metaAddr = typeof recipientMetaAddress === 'string'
|
|
366
|
+
? parseNEARStealthMetaAddress(recipientMetaAddress)
|
|
367
|
+
: recipientMetaAddress
|
|
368
|
+
|
|
369
|
+
// Validate chain
|
|
370
|
+
if (metaAddr.chain !== 'near') {
|
|
371
|
+
throw new ValidationError(
|
|
372
|
+
`Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
|
|
373
|
+
'recipientMetaAddress'
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Validate token contract
|
|
378
|
+
if (!isValidAccountId(tokenContract)) {
|
|
379
|
+
throw new ValidationError('Invalid token contract account ID', 'tokenContract')
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Validate amount
|
|
383
|
+
if (amount <= 0n) {
|
|
384
|
+
throw new ValidationError('amount must be greater than 0', 'amount')
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Validate msg is valid JSON
|
|
388
|
+
try {
|
|
389
|
+
JSON.parse(msg)
|
|
390
|
+
} catch {
|
|
391
|
+
throw new ValidationError('msg must be valid JSON', 'msg')
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Generate stealth address
|
|
395
|
+
const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
|
|
396
|
+
|
|
397
|
+
// Create announcement memo
|
|
398
|
+
const announcementMemo = createAnnouncementMemo(
|
|
399
|
+
stealthAddress.ephemeralPublicKey,
|
|
400
|
+
stealthAddress.viewTag
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
// Build ft_transfer_call args
|
|
404
|
+
const transferMemo = memo ? `${announcementMemo}|${memo}` : announcementMemo
|
|
405
|
+
const args = JSON.stringify({
|
|
406
|
+
receiver_id: implicitAccountId,
|
|
407
|
+
amount: amount.toString(),
|
|
408
|
+
memo: transferMemo,
|
|
409
|
+
msg,
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
// Build function call action with extra gas for callback
|
|
413
|
+
const totalGas = FT_TRANSFER_CALL_TOTAL_GAS > receiverGas
|
|
414
|
+
? FT_TRANSFER_CALL_TOTAL_GAS
|
|
415
|
+
: receiverGas + 50_000_000_000_000n
|
|
416
|
+
|
|
417
|
+
const actions: NEARAction[] = [
|
|
418
|
+
{
|
|
419
|
+
type: 'FunctionCall',
|
|
420
|
+
params: {
|
|
421
|
+
methodName: 'ft_transfer_call',
|
|
422
|
+
args,
|
|
423
|
+
gas: totalGas,
|
|
424
|
+
deposit: ONE_YOCTO,
|
|
425
|
+
} as NEARFunctionCallAction,
|
|
426
|
+
},
|
|
427
|
+
]
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
actions,
|
|
431
|
+
receiverId: tokenContract,
|
|
432
|
+
stealthAddress,
|
|
433
|
+
stealthAccountId: implicitAccountId,
|
|
434
|
+
announcementMemo,
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// ─── Batch Token Transfers ────────────────────────────────────────────────────
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Build batch privacy-wrapped token transfers
|
|
442
|
+
*
|
|
443
|
+
* Sends tokens to multiple stealth addresses in a single transaction,
|
|
444
|
+
* improving efficiency and reducing transaction costs.
|
|
445
|
+
*
|
|
446
|
+
* Note: NEAR doesn't support batch ft_transfer in a single action,
|
|
447
|
+
* so this creates multiple function call actions.
|
|
448
|
+
*
|
|
449
|
+
* @param params - Batch transfer parameters
|
|
450
|
+
* @returns Batch transfer build
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* ```typescript
|
|
454
|
+
* const result = buildBatchPrivateTokenTransfer({
|
|
455
|
+
* tokenContract: 'usdc.near',
|
|
456
|
+
* transfers: [
|
|
457
|
+
* { recipientMetaAddress: 'sip:near:0x...', amount: 100_000_000n },
|
|
458
|
+
* { recipientMetaAddress: 'sip:near:0x...', amount: 50_000_000n },
|
|
459
|
+
* ],
|
|
460
|
+
* decimals: 6,
|
|
461
|
+
* hideAmounts: true,
|
|
462
|
+
* })
|
|
463
|
+
*
|
|
464
|
+
* // Execute all transfers in one transaction
|
|
465
|
+
* ```
|
|
466
|
+
*/
|
|
467
|
+
export function buildBatchPrivateTokenTransfer(
|
|
468
|
+
params: BatchTokenTransferParams
|
|
469
|
+
): BatchTokenTransferResult {
|
|
470
|
+
const {
|
|
471
|
+
tokenContract,
|
|
472
|
+
transfers,
|
|
473
|
+
decimals,
|
|
474
|
+
hideAmounts = false,
|
|
475
|
+
} = params
|
|
476
|
+
|
|
477
|
+
// Validate token contract
|
|
478
|
+
if (!isValidAccountId(tokenContract)) {
|
|
479
|
+
throw new ValidationError('Invalid token contract account ID', 'tokenContract')
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Validate transfers
|
|
483
|
+
if (!transfers || transfers.length === 0) {
|
|
484
|
+
throw new ValidationError('At least one transfer is required', 'transfers')
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (transfers.length > 10) {
|
|
488
|
+
throw new ValidationError(
|
|
489
|
+
'Maximum 10 transfers per batch (gas limit)',
|
|
490
|
+
'transfers'
|
|
491
|
+
)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Validate decimals if hiding amounts
|
|
495
|
+
if (hideAmounts && decimals === undefined) {
|
|
496
|
+
throw new ValidationError(
|
|
497
|
+
'decimals is required when hideAmounts is true',
|
|
498
|
+
'decimals'
|
|
499
|
+
)
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const results: BatchTokenTransferResult['transfers'] = []
|
|
503
|
+
const actions: NEARAction[] = []
|
|
504
|
+
let totalAmount = 0n
|
|
505
|
+
|
|
506
|
+
for (const transfer of transfers) {
|
|
507
|
+
const { recipientMetaAddress, amount } = transfer
|
|
508
|
+
|
|
509
|
+
// Parse meta-address if string
|
|
510
|
+
const metaAddr = typeof recipientMetaAddress === 'string'
|
|
511
|
+
? parseNEARStealthMetaAddress(recipientMetaAddress)
|
|
512
|
+
: recipientMetaAddress
|
|
513
|
+
|
|
514
|
+
// Validate chain
|
|
515
|
+
if (metaAddr.chain !== 'near') {
|
|
516
|
+
throw new ValidationError(
|
|
517
|
+
`Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
|
|
518
|
+
'recipientMetaAddress'
|
|
519
|
+
)
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Validate amount
|
|
523
|
+
if (amount <= 0n) {
|
|
524
|
+
throw new ValidationError('amount must be greater than 0', 'amount')
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Generate stealth address
|
|
528
|
+
const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
|
|
529
|
+
|
|
530
|
+
// Create announcement memo
|
|
531
|
+
const announcementMemo = createAnnouncementMemo(
|
|
532
|
+
stealthAddress.ephemeralPublicKey,
|
|
533
|
+
stealthAddress.viewTag
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
// Create commitment if hiding amounts
|
|
537
|
+
let commitment: NEP141TokenCommitment | undefined
|
|
538
|
+
if (hideAmounts && decimals !== undefined) {
|
|
539
|
+
commitment = commitNEP141Token(amount, tokenContract, decimals)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Build transfer memo
|
|
543
|
+
const transferMemo = commitment
|
|
544
|
+
? `${announcementMemo}|c:${commitment.commitment.slice(2, 18)}`
|
|
545
|
+
: announcementMemo
|
|
546
|
+
|
|
547
|
+
// Build ft_transfer args
|
|
548
|
+
const args = JSON.stringify({
|
|
549
|
+
receiver_id: implicitAccountId,
|
|
550
|
+
amount: amount.toString(),
|
|
551
|
+
memo: transferMemo,
|
|
552
|
+
})
|
|
553
|
+
|
|
554
|
+
// Add action
|
|
555
|
+
actions.push({
|
|
556
|
+
type: 'FunctionCall',
|
|
557
|
+
params: {
|
|
558
|
+
methodName: 'ft_transfer',
|
|
559
|
+
args,
|
|
560
|
+
gas: DEFAULT_GAS,
|
|
561
|
+
deposit: ONE_YOCTO,
|
|
562
|
+
} as NEARFunctionCallAction,
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
results.push({
|
|
566
|
+
stealthAddress,
|
|
567
|
+
stealthAccountId: implicitAccountId,
|
|
568
|
+
announcementMemo,
|
|
569
|
+
amount,
|
|
570
|
+
commitment,
|
|
571
|
+
})
|
|
572
|
+
|
|
573
|
+
totalAmount += amount
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return {
|
|
577
|
+
transfers: results,
|
|
578
|
+
actions,
|
|
579
|
+
receiverId: tokenContract,
|
|
580
|
+
totalAmount,
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// ─── Storage Deposit Helpers ──────────────────────────────────────────────────
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Build batch storage deposit for multiple stealth accounts
|
|
588
|
+
*
|
|
589
|
+
* Pre-registers storage for multiple stealth accounts before sending tokens.
|
|
590
|
+
*
|
|
591
|
+
* @param stealthAccountIds - List of stealth implicit account IDs
|
|
592
|
+
* @param tokenContract - Token contract address
|
|
593
|
+
* @param amountPerAccount - Storage deposit per account (default: 0.00125 NEAR)
|
|
594
|
+
* @returns Storage deposit actions
|
|
595
|
+
*/
|
|
596
|
+
export function buildBatchStorageDeposit(
|
|
597
|
+
stealthAccountIds: string[],
|
|
598
|
+
tokenContract: string,
|
|
599
|
+
amountPerAccount: bigint = STORAGE_DEPOSIT_DEFAULT
|
|
600
|
+
): NEARAction[] {
|
|
601
|
+
if (!isValidAccountId(tokenContract)) {
|
|
602
|
+
throw new ValidationError('Invalid token contract account ID', 'tokenContract')
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (!stealthAccountIds || stealthAccountIds.length === 0) {
|
|
606
|
+
throw new ValidationError('At least one account ID is required', 'stealthAccountIds')
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (stealthAccountIds.length > 20) {
|
|
610
|
+
throw new ValidationError(
|
|
611
|
+
'Maximum 20 storage deposits per batch (gas limit)',
|
|
612
|
+
'stealthAccountIds'
|
|
613
|
+
)
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return stealthAccountIds.map(accountId => {
|
|
617
|
+
const args = JSON.stringify({
|
|
618
|
+
account_id: accountId,
|
|
619
|
+
})
|
|
620
|
+
|
|
621
|
+
return {
|
|
622
|
+
type: 'FunctionCall' as const,
|
|
623
|
+
params: {
|
|
624
|
+
methodName: 'storage_deposit',
|
|
625
|
+
args,
|
|
626
|
+
gas: DEFAULT_GAS,
|
|
627
|
+
deposit: amountPerAccount,
|
|
628
|
+
} as NEARFunctionCallAction,
|
|
629
|
+
}
|
|
630
|
+
})
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Build storage withdraw action
|
|
635
|
+
*
|
|
636
|
+
* Withdraw excess storage deposit from a token contract.
|
|
637
|
+
*
|
|
638
|
+
* @param amount - Amount to withdraw (null for all available)
|
|
639
|
+
* @returns Storage withdraw action
|
|
640
|
+
*/
|
|
641
|
+
export function buildStorageWithdraw(amount?: bigint): NEARAction {
|
|
642
|
+
const args = amount !== undefined
|
|
643
|
+
? JSON.stringify({ amount: amount.toString() })
|
|
644
|
+
: '{}'
|
|
645
|
+
|
|
646
|
+
return {
|
|
647
|
+
type: 'FunctionCall',
|
|
648
|
+
params: {
|
|
649
|
+
methodName: 'storage_withdraw',
|
|
650
|
+
args,
|
|
651
|
+
gas: DEFAULT_GAS,
|
|
652
|
+
deposit: ONE_YOCTO,
|
|
653
|
+
} as NEARFunctionCallAction,
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Build storage unregister action
|
|
659
|
+
*
|
|
660
|
+
* Unregister from a token contract and reclaim storage deposit.
|
|
661
|
+
* Only works if token balance is zero.
|
|
662
|
+
*
|
|
663
|
+
* @param force - Force unregister even if balance > 0 (burns tokens)
|
|
664
|
+
* @returns Storage unregister action
|
|
665
|
+
*/
|
|
666
|
+
export function buildStorageUnregister(force: boolean = false): NEARAction {
|
|
667
|
+
const args = JSON.stringify({ force })
|
|
668
|
+
|
|
669
|
+
return {
|
|
670
|
+
type: 'FunctionCall',
|
|
671
|
+
params: {
|
|
672
|
+
methodName: 'storage_unregister',
|
|
673
|
+
args,
|
|
674
|
+
gas: DEFAULT_GAS,
|
|
675
|
+
deposit: ONE_YOCTO,
|
|
676
|
+
} as NEARFunctionCallAction,
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// ─── Token Metadata ───────────────────────────────────────────────────────────
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Parse ft_metadata response
|
|
684
|
+
*
|
|
685
|
+
* @param response - Raw metadata response from RPC
|
|
686
|
+
* @returns Parsed token metadata
|
|
687
|
+
*/
|
|
688
|
+
export function parseTokenMetadata(response: unknown): NEP141TokenMetadata {
|
|
689
|
+
if (!response || typeof response !== 'object') {
|
|
690
|
+
throw new ValidationError('Invalid metadata response', 'response')
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const data = response as Record<string, unknown>
|
|
694
|
+
|
|
695
|
+
return {
|
|
696
|
+
spec: String(data.spec || 'ft-1.0.0'),
|
|
697
|
+
name: String(data.name || 'Unknown Token'),
|
|
698
|
+
symbol: String(data.symbol || '???'),
|
|
699
|
+
icon: data.icon ? String(data.icon) : undefined,
|
|
700
|
+
reference: data.reference ? String(data.reference) : undefined,
|
|
701
|
+
referenceHash: data.reference_hash ? String(data.reference_hash) : undefined,
|
|
702
|
+
decimals: Number(data.decimals || 0),
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Format token amount for display
|
|
708
|
+
*
|
|
709
|
+
* @param amount - Amount in smallest units
|
|
710
|
+
* @param decimals - Token decimals
|
|
711
|
+
* @param symbol - Token symbol
|
|
712
|
+
* @returns Formatted amount string (e.g., "100.50 USDC")
|
|
713
|
+
*/
|
|
714
|
+
export function formatTokenAmount(
|
|
715
|
+
amount: bigint,
|
|
716
|
+
decimals: number,
|
|
717
|
+
symbol?: string
|
|
718
|
+
): string {
|
|
719
|
+
const str = amount.toString().padStart(decimals + 1, '0')
|
|
720
|
+
const whole = str.slice(0, -decimals) || '0'
|
|
721
|
+
const fraction = str.slice(-decimals).replace(/0+$/, '')
|
|
722
|
+
|
|
723
|
+
const formatted = fraction ? `${whole}.${fraction}` : whole
|
|
724
|
+
|
|
725
|
+
return symbol ? `${formatted} ${symbol}` : formatted
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* Parse token amount from display string
|
|
730
|
+
*
|
|
731
|
+
* @param displayAmount - Human-readable amount (e.g., "100.50")
|
|
732
|
+
* @param decimals - Token decimals
|
|
733
|
+
* @returns Amount in smallest units
|
|
734
|
+
*/
|
|
735
|
+
export function parseTokenAmount(displayAmount: string, decimals: number): bigint {
|
|
736
|
+
// Remove any symbol suffix
|
|
737
|
+
const cleaned = displayAmount.replace(/[^0-9.]/g, '').trim()
|
|
738
|
+
|
|
739
|
+
const [whole, fraction = ''] = cleaned.split('.')
|
|
740
|
+
const paddedFraction = fraction.padEnd(decimals, '0').slice(0, decimals)
|
|
741
|
+
|
|
742
|
+
return BigInt(whole + paddedFraction)
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// ─── Commitment Verification ──────────────────────────────────────────────────
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Extract commitment hash from transfer memo
|
|
749
|
+
*
|
|
750
|
+
* @param memo - Transfer memo string
|
|
751
|
+
* @returns Commitment hash prefix if present
|
|
752
|
+
*/
|
|
753
|
+
export function extractCommitmentFromMemo(memo: string): string | null {
|
|
754
|
+
const match = memo.match(/\|c:([a-f0-9]{16})/)
|
|
755
|
+
return match ? match[1] : null
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Verify that a commitment matches the expected prefix in memo
|
|
760
|
+
*
|
|
761
|
+
* @param commitment - The full commitment
|
|
762
|
+
* @param memo - Transfer memo
|
|
763
|
+
* @returns True if commitment matches memo prefix
|
|
764
|
+
*/
|
|
765
|
+
export function verifyCommitmentInMemo(
|
|
766
|
+
commitment: HexString,
|
|
767
|
+
memo: string
|
|
768
|
+
): boolean {
|
|
769
|
+
const extracted = extractCommitmentFromMemo(memo)
|
|
770
|
+
if (!extracted) return false
|
|
771
|
+
|
|
772
|
+
// Compare prefix (first 16 hex chars after 0x)
|
|
773
|
+
const commitmentPrefix = commitment.slice(2, 18)
|
|
774
|
+
return commitmentPrefix === extracted
|
|
775
|
+
}
|