@hinkal/common 0.2.38 → 0.2.39
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
CHANGED
|
@@ -80,9 +80,95 @@ type HinkalConfig = {
|
|
|
80
80
|
* Indicator controlling wether the proof should be constructed remotely in secure enclave. Defaults to true.
|
|
81
81
|
*/
|
|
82
82
|
generateProofRemotely?: boolean;
|
|
83
|
+
|
|
84
|
+
/** Disables automatic merkle tree updates. Defaults to false. */
|
|
85
|
+
disableMerkleTreeUpdates?: boolean;
|
|
86
|
+
|
|
87
|
+
/** Override which Tron chain this Hinkal instance targets. */
|
|
88
|
+
tronChainOverride?: number;
|
|
83
89
|
};
|
|
84
90
|
```
|
|
85
91
|
|
|
92
|
+
### Identity persistence
|
|
93
|
+
|
|
94
|
+
When a user connects their wallet, they sign a fixed login message to authenticate with Hinkal. That signature defines their Hinkal identity. Their shielded balances, transaction ability, and all private operations depend on it.
|
|
95
|
+
|
|
96
|
+
Most wallets return the same signature every time for the same message. Some do not. Smart contract wallets, certain hardware wallets, and other non-deterministic signers may produce a different signature on each login, even for the same address and message.
|
|
97
|
+
|
|
98
|
+
When that happens, a returning user appears as a new account. Funds deposited in an earlier session remain tied to the original identity and are not accessible from the new one.
|
|
99
|
+
|
|
100
|
+
Use `storeAndGetInitialSignature` to keep identity stable across sessions. It stores the user's first login signature server-side and returns that same signature on every later login. The user still signs each session to prove wallet ownership, but the SDK always initializes with the original signature.
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
function storeAndGetInitialSignature(
|
|
104
|
+
authSignature: string,
|
|
105
|
+
isSolanaLedger?: boolean,
|
|
106
|
+
txMessageForSolanaLedger?: string,
|
|
107
|
+
): Promise<string>;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Parameters:
|
|
111
|
+
|
|
112
|
+
- `authSignature` — signature from the current login session
|
|
113
|
+
- `isSolanaLedger` — set to `true` for a Solana Ledger wallet. Defaults to `false`
|
|
114
|
+
- `txMessageForSolanaLedger` — base64-encoded transaction message used for Solana Ledger authentication. Required when `isSolanaLedger` is `true`
|
|
115
|
+
|
|
116
|
+
Typical flow:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const authSignature = await hinkal.signHinkalMessage();
|
|
120
|
+
const initialSignature = await hinkal.storeAndGetInitialSignature(authSignature);
|
|
121
|
+
hinkal.initUserKeysWithSignature(initialSignature);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Call this once per session, after wallet connection and before fetching balances or submitting transactions.
|
|
125
|
+
|
|
126
|
+
**Security**
|
|
127
|
+
|
|
128
|
+
The stored signature is protected at every stage. Before leaving the client, the signature is encrypted with hybrid encryption. The payload is encrypted with a symmetric key, and that key is encrypted with the enclave's public key.
|
|
129
|
+
|
|
130
|
+
Inside the secure enclave, Google Cloud KMS decrypts the symmetric key. Only then is the signature decrypted. The plaintext signature never leaves the enclave unprotected.
|
|
131
|
+
|
|
132
|
+
At rest, only the encrypted signature and encrypted key are stored in the database. A caller cannot retrieve a stored signature by wallet address alone. Each request must include any valid signature that proves wallet ownership.
|
|
133
|
+
|
|
134
|
+
Requests that fail this check are rejected. The first signature stored for a given address is never replaced. Later logins only use a fresh signature to authenticate retrieval of the original.
|
|
135
|
+
|
|
136
|
+
You should use this function in any wallet-connected application where users may reconnect across sessions, especially when supporting smart contract wallets. It is not necessary if your wallet produces deterministic signatures for the same login message on every session — in that case, calling `initUserKeys` or `initUserKeysWithSignature` with the fresh signature is sufficient. It is also not needed if you persist the signature yourself, or if you use seed-phrase-based login through `initUserKeysFromSeedPhrases`.
|
|
137
|
+
|
|
138
|
+
**Solana Ledger wallets**
|
|
139
|
+
|
|
140
|
+
For standard EVM and Solana wallets, authentication uses a plain message signature. Call `signHinkalMessage` and pass the result to `storeAndGetInitialSignature` without extra parameters.
|
|
141
|
+
|
|
142
|
+
Solana Ledger wallets cannot reliably sign arbitrary UTF-8 messages. For those wallets, Hinkal uses a deterministic empty Solana transaction instead. The transaction uses a fixed blockhash and block height, so signing it always returns the same result.
|
|
143
|
+
|
|
144
|
+
Use `signSolanaLedgerMessage` to get both the signature and the transaction message, then pass them to `storeAndGetInitialSignature`:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const isSolanaLedger = hinkal.getProviderAdapter().isSolanaLedger?.() ?? false;
|
|
148
|
+
let authSignature: string;
|
|
149
|
+
let txMessageForSolanaLedger: string | undefined;
|
|
150
|
+
|
|
151
|
+
if (isSolanaLedger) {
|
|
152
|
+
const ledgerAuth = await hinkal.signSolanaLedgerMessage();
|
|
153
|
+
authSignature = ledgerAuth.signature;
|
|
154
|
+
txMessageForSolanaLedger = ledgerAuth.txMessageForSolanaLedger;
|
|
155
|
+
} else {
|
|
156
|
+
authSignature = await hinkal.signHinkalMessage();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const initialSignature = await hinkal.storeAndGetInitialSignature(
|
|
160
|
+
authSignature,
|
|
161
|
+
isSolanaLedger,
|
|
162
|
+
txMessageForSolanaLedger,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
hinkal.initUserKeysWithSignature(initialSignature);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
On return visits, the user must sign the same deterministic transaction again to authenticate. The enclave verifies the fresh signature against `txMessageForSolanaLedger`, not against a plain login message.
|
|
169
|
+
|
|
170
|
+
If your application caches the transaction message locally between sessions, pass the cached value as `txMessageForSolanaLedger` so the enclave can verify the correct payload.
|
|
171
|
+
|
|
86
172
|
### Shielded balance
|
|
87
173
|
|
|
88
174
|
Shielded balances are encrypted token holdings stored within the Hinkal protocol. Unlike regular blockchain balances that are publicly visible, shielded balances are hidden from external observers, providing privacy for your assets. After initializing the Hinkal object, you can access and calculate your shielded balances:
|
|
@@ -188,9 +274,93 @@ where:
|
|
|
188
274
|
- `erc20Token` is the token to transfer (only single token transfers are supported for this method)
|
|
189
275
|
- `recipientAmounts` is an array of amounts to send to each recipient (in the token's smallest unit)
|
|
190
276
|
- `recipientAddresses` is an array of public addresses that will receive the funds
|
|
191
|
-
- `txCompletionTime` (optional)
|
|
277
|
+
- `txCompletionTime` (optional) is a Unix timestamp in seconds by which all scheduled withdrawals must complete
|
|
192
278
|
- `preEstimateGas` If true (default), the gas needed for the operation will be estimated before executing the deposit. This can help avoid failed transactions due to "out of gas" error.
|
|
193
279
|
|
|
280
|
+
### Private Send from Public to Public addresses (extended)
|
|
281
|
+
|
|
282
|
+
Private Send from Public to Public addresses (extended) follows the same flow as `depositAndWithdraw`. Tokens are shielded from the sender's public address, then withdrawn to one or more recipient public addresses on a relayer schedule. In addition to the deposit transaction hash, it returns a `scheduleId` that you can use to check the status of each scheduled withdrawal.
|
|
283
|
+
|
|
284
|
+
A user can perform an extended private transfer between public addresses using:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
function depositAndWithdrawExtended(
|
|
288
|
+
erc20Token: ERC20Token,
|
|
289
|
+
recipientAmounts: bigint[],
|
|
290
|
+
recipientAddresses: string[],
|
|
291
|
+
txCompletionTime?: number,
|
|
292
|
+
preEstimateGas?: boolean,
|
|
293
|
+
): Promise<DepositAndSendExtendedResult>;
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
where:
|
|
297
|
+
|
|
298
|
+
- `erc20Token` is the token to transfer (only single token transfers are supported for this method)
|
|
299
|
+
- `recipientAmounts` is an array of amounts to send to each recipient (in the token's smallest unit)
|
|
300
|
+
- `recipientAddresses` is an array of public addresses that will receive the funds
|
|
301
|
+
- `txCompletionTime` (optional) is a Unix timestamp in seconds by which all scheduled withdrawals must complete
|
|
302
|
+
- `preEstimateGas` If true (default), the gas needed for the operation will be estimated before executing the deposit. This can help avoid failed transactions due to "out of gas" error.
|
|
303
|
+
|
|
304
|
+
The function returns:
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
type DepositAndSendExtendedResult = {
|
|
308
|
+
depositTxHash: string;
|
|
309
|
+
scheduleId: string;
|
|
310
|
+
};
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
where:
|
|
314
|
+
|
|
315
|
+
- `depositTxHash` is the on-chain hash of the deposit transaction
|
|
316
|
+
- `scheduleId` is the relayer schedule identifier used to fetch withdrawal status
|
|
317
|
+
|
|
318
|
+
### Checking scheduled send status
|
|
319
|
+
|
|
320
|
+
After calling `depositAndWithdrawExtended`, a user can fetch the current status of the scheduled withdrawals using the returned `scheduleId`:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
function checkSendTransactionStatus(scheduleId: string): Promise<ScheduledTransactionByIdResponse>;
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
where:
|
|
327
|
+
|
|
328
|
+
- `scheduleId` is the schedule identifier returned from an extended deposit-and-send call
|
|
329
|
+
|
|
330
|
+
The function returns:
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
type ScheduledTransactionByIdResponse = {
|
|
334
|
+
scheduleId: string;
|
|
335
|
+
chainId: number;
|
|
336
|
+
transactions: ScheduledTransactionItemStatus[];
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
type ScheduledTransactionItemStatus = {
|
|
340
|
+
status: ScheduledTransactionStatus;
|
|
341
|
+
scheduledTime: string;
|
|
342
|
+
txHash: string | null;
|
|
343
|
+
};
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
where:
|
|
347
|
+
|
|
348
|
+
- `scheduleId` is the schedule identifier
|
|
349
|
+
- `chainId` is the chain on which the scheduled transactions are executed
|
|
350
|
+
- `transactions` is the list of scheduled withdrawals, one entry per recipient
|
|
351
|
+
- `status` indicates the current state of a scheduled withdrawal
|
|
352
|
+
- `scheduledTime` is the planned execution time in ISO 8601 format
|
|
353
|
+
- `txHash` is the on-chain transaction hash once the withdrawal is sent on-chain, or `null` before submission
|
|
354
|
+
|
|
355
|
+
Possible values for `ScheduledTransactionStatus` are:
|
|
356
|
+
|
|
357
|
+
- `pending` — the withdrawal is scheduled and waiting for its execution time
|
|
358
|
+
- `processing` — the relayer is currently submitting the withdrawal transaction on-chain
|
|
359
|
+
- `waiting_for_relayer` — the relayer is busy; the withdrawal is queued to start
|
|
360
|
+
- `sent_on_chain` — the withdrawal was submitted on-chain and `txHash` is available
|
|
361
|
+
- `completed` — the withdrawal was confirmed on-chain
|
|
362
|
+
- `failed` — the withdrawal transaction failed
|
|
363
|
+
|
|
194
364
|
### Swapping tokens from the shielded balance
|
|
195
365
|
|
|
196
366
|
Swapping allows you to exchange tokens directly from your shielded balance without revealing your identity. The swap is executed through integrated DEX protocols (Uniswap, 1Inch, Odos) while keeping your transaction private. Your tokens are withdrawn from your shielded balance, swapped through the specified protocol, and the resulting tokens are deposited back into your shielded balance—all in a single private transaction.
|
|
@@ -342,15 +512,19 @@ In this example:
|
|
|
342
512
|
|
|
343
513
|
Hinkal SDK is available on the following blockchain networks:
|
|
344
514
|
|
|
345
|
-
| Chain
|
|
346
|
-
|
|
|
347
|
-
| Ethereum
|
|
348
|
-
|
|
|
349
|
-
|
|
|
350
|
-
|
|
|
351
|
-
|
|
|
352
|
-
| Solana
|
|
353
|
-
| Tron
|
|
515
|
+
| Chain | Chain ID | Status |
|
|
516
|
+
| --------------- | ---------- | ------- |
|
|
517
|
+
| Ethereum | 1 | ✅ Live |
|
|
518
|
+
| Arbitrum | 42161 | ✅ Live |
|
|
519
|
+
| Optimism | 10 | ✅ Live |
|
|
520
|
+
| Polygon | 137 | ✅ Live |
|
|
521
|
+
| Base | 8453 | ✅ Live |
|
|
522
|
+
| Solana | 501 | ✅ Live |
|
|
523
|
+
| Tron | 728126428 | ✅ Live |
|
|
524
|
+
| Tempo | 4217 | ✅ Live |
|
|
525
|
+
| Arc Testnet | 5042002 | ✅ Live |
|
|
526
|
+
| Sepolia Testnet | 11155111 | ✅ Live |
|
|
527
|
+
| Tron Nile | 3448148188 | ✅ Live |
|
|
354
528
|
|
|
355
529
|
Each chain supports the full suite of Hinkal privacy features including shielding, transfers, and confidential interactions with DeFi protocols.
|
|
356
530
|
|
package/package.json
CHANGED
package/webworker/package.json
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
var e = /* @__PURE__ */ ((r) => (r.ZKProof = "ZKProof", r.SnarkJS = "SnarkJS", r.UTXO = "UTXO", r))(e || {});
|
|
15
15
|
|
|
16
16
|
const n = async () => ({
|
|
17
|
-
[e.ZKProof]: await getWorkerURL(domain + '/0.2.
|
|
18
|
-
[e.SnarkJS]: await getWorkerURL(domain + '/0.2.
|
|
19
|
-
[e.UTXO]: await getWorkerURL(domain + '/0.2.
|
|
17
|
+
[e.ZKProof]: await getWorkerURL(domain + '/0.2.39/' + 'zkProofWorkerLauncher.js'),
|
|
18
|
+
[e.SnarkJS]: await getWorkerURL(domain + '/0.2.39/' + 'snarkjsWorkerLauncher.js'),
|
|
19
|
+
[e.UTXO]: await getWorkerURL(domain + '/0.2.39/' + 'utxoWorkerLauncher.js'),
|
|
20
20
|
});
|
|
21
21
|
exports.getWorkerViteURL = n;
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
var e = /* @__PURE__ */ ((r) => (r.ZKProof = "ZKProof", r.SnarkJS = "SnarkJS", r.UTXO = "UTXO", r))(e || {});
|
|
15
15
|
|
|
16
16
|
const n = async () => ({
|
|
17
|
-
[e.ZKProof]: await getWorkerURL(domain + '/0.2.
|
|
18
|
-
[e.SnarkJS]: await getWorkerURL(domain + '/0.2.
|
|
19
|
-
[e.UTXO]: await getWorkerURL(domain + '/0.2.
|
|
17
|
+
[e.ZKProof]: await getWorkerURL(domain + '/0.2.39/' + 'zkProofWorkerLauncher.js'),
|
|
18
|
+
[e.SnarkJS]: await getWorkerURL(domain + '/0.2.39/' + 'snarkjsWorkerLauncher.js'),
|
|
19
|
+
[e.UTXO]: await getWorkerURL(domain + '/0.2.39/' + 'utxoWorkerLauncher.js'),
|
|
20
20
|
});
|
|
21
21
|
export { n as getWorkerViteURL };
|