@rhea-finance/confidential-swap 0.1.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/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/adapters/index.cjs +287 -0
- package/dist/adapters/index.cjs.map +1 -0
- package/dist/adapters/index.d.cts +42 -0
- package/dist/adapters/index.d.ts +42 -0
- package/dist/adapters/index.js +258 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/aggregation.cjs +186 -0
- package/dist/aggregation.cjs.map +1 -0
- package/dist/aggregation.d.cts +35 -0
- package/dist/aggregation.d.ts +35 -0
- package/dist/aggregation.js +158 -0
- package/dist/aggregation.js.map +1 -0
- package/dist/api-DenG9sWp.d.cts +50 -0
- package/dist/api-cazA5IdP.d.ts +50 -0
- package/dist/index.cjs +1320 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +118 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.js +1272 -0
- package/dist/index.js.map +1 -0
- package/dist/types-Bq8OZRUK.d.cts +268 -0
- package/dist/types-Bq8OZRUK.d.ts +268 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rhea Finance
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @rhea-finance/confidential-swap
|
|
2
|
+
|
|
3
|
+
Independent TypeScript SDK extracted from the confidential trade flow in `multi-chain-lending`. Browser and Node.js 20+; ESM, CJS and type declarations. No React, browser globals, wallet connections, private keys or RPC credentials are embedded.
|
|
4
|
+
|
|
5
|
+
## Wallet roles
|
|
6
|
+
|
|
7
|
+
The linking wallet signs confidential authorization and withdrawal intents. Supported standards are NEAR NEP-413, EVM ERC-191, Solana raw Ed25519, and Tron TIP-191. All signatures are verified locally using Noble cryptography.
|
|
8
|
+
|
|
9
|
+
The funding wallet performs source-chain transfers, approvals, chain switching and funding swaps. It can be a different wallet on a different chain. BTC, Zcash, Aptos and Sui can fund through a supplied funding adapter; they are not linking wallets.
|
|
10
|
+
|
|
11
|
+
Default `resolveLinkingWallet` selection prefers the connected source kind, then NEAR, EVM, Solana, Tron. An explicit preferred wallet overrides that priority. Quote plans freeze the selected account and public key; execution will not silently switch identity.
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pnpm install
|
|
17
|
+
pnpm check
|
|
18
|
+
pnpm test:repeat
|
|
19
|
+
pnpm check:live-readonly # optional network-only registry check; no signatures or funds
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For package consumers: `pnpm add @rhea-finance/confidential-swap` after publication, or install a locally packed tarball. This repository has not been published automatically.
|
|
23
|
+
|
|
24
|
+
## Client
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import {
|
|
28
|
+
HttpConfidentialApi,
|
|
29
|
+
createConfidentialSwapClient,
|
|
30
|
+
type FundingAdapter,
|
|
31
|
+
} from '@rhea-finance/confidential-swap';
|
|
32
|
+
import { createEvmSigningAdapter } from '@rhea-finance/confidential-swap/adapters';
|
|
33
|
+
|
|
34
|
+
const api = new HttpConfidentialApi({
|
|
35
|
+
directUrl: 'https://1click.chaindefuser.com/v0',
|
|
36
|
+
proxyUrl: 'https://api.rhea.finance/proxy/1click/v0',
|
|
37
|
+
indexerUrl: 'https://api.rhea.finance',
|
|
38
|
+
nearRpcUrl: 'https://rpc.mainnet.near.org',
|
|
39
|
+
// Reference app uses signed-payload authorization for POST /private/withdraws.
|
|
40
|
+
// Select 'bearer' only when that matches your backend contract.
|
|
41
|
+
withdrawAuthorization: 'signed-payload',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const linking = createEvmSigningAdapter(() => connectedEvmSigner);
|
|
45
|
+
const funding: FundingAdapter = sourceChainAdapter;
|
|
46
|
+
const client = createConfidentialSwapClient({
|
|
47
|
+
api,
|
|
48
|
+
signingAdapters: [linking],
|
|
49
|
+
fundingAdapters: [funding],
|
|
50
|
+
// Add fundingSwapAdapter for non-DIRECT routes.
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const plan = await client.quote({
|
|
54
|
+
sourceToken,
|
|
55
|
+
destinationToken,
|
|
56
|
+
amount: '1000000', // smallest-unit integer string, never a JS floating-point amount
|
|
57
|
+
sourceWallet: await funding.getIdentity(),
|
|
58
|
+
linkingWallet: await linking.getIdentity(),
|
|
59
|
+
recipients: destinationAddresses,
|
|
60
|
+
slippageBps: 50, // 0.5 percent
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Display plan.previews, plan.minAmountOut and the selected wallet identities for review.
|
|
64
|
+
const result = await client.execute(plan, {
|
|
65
|
+
signal: controller.signal,
|
|
66
|
+
onProgress: snapshot => updateProgress(snapshot),
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The example assumes the application's existing wallet, asset, funding adapter and progress objects. The SDK does not connect wallets or manage UI. Connect and choose those objects in the application; do not pass private keys into the SDK.
|
|
71
|
+
|
|
72
|
+
`Token.assetId` identifies the registry asset. `blockchain` names its chain. `contractAddress` identifies its actual on-chain token. For numeric EVM funding identities supply the matching token `swapChain` (e.g. `"1"`); `swapAddress` explicitly maps an asset to the aggregation SDK's token address/native sentinel. No arbitrary EVM chain is guessed from `evm` kind alone.
|
|
73
|
+
|
|
74
|
+
`preview` accepts an optional linking identity and returns `executable: false`. A placeholder identity is display-only. Preview/quote may allocate deposit addresses on the backend, but neither signs nor broadcasts funds. `quote` requires a real linking identity. Default fees match the reference app: 2 bps to `crosschaindexfee.near`, referral `rhea`; supply `appFees: []` or your own fees explicitly when needed.
|
|
75
|
+
|
|
76
|
+
## Funding adapters and paths
|
|
77
|
+
|
|
78
|
+
`FundingAdapter.getIdentity` returns `{ kind, accountId, chain }`. Its `validate` checks capability and the source chain without sending funds. Its `transfer` receives the real source token, smallest-unit amount, deposit address, optional memo and stable execution ID. Return a source transaction hash. Implement chain-specific transfer logic with the application's existing wallet SDK; an adapter must check identity again immediately before signing/broadcasting.
|
|
79
|
+
|
|
80
|
+
For non-DIRECT funding, the funding adapter still validates the source wallet and chain, while `FundingSwapAdapter` performs quote/build/execute/report/status. Its quote data must be public and JSON-serializable. Its executor must use exactly the supplied source identity, chain and deposit recipient.
|
|
81
|
+
|
|
82
|
+
| Path | Waiting sequence |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| DIRECT | Transfer from the source wallet; wait for confidential deposit and credited balance |
|
|
85
|
+
| SAME_CHAIN_SWAP | Swap to FLEX_INPUT, report, wait only for confidential deposit and balance |
|
|
86
|
+
| CROSS_CHAIN_SWAP | Swap to FLEX_INPUT, report, wait for swap record success, then deposit and balance |
|
|
87
|
+
|
|
88
|
+
All paths authorize the linking identity before sending source funds. Routing prefers registered direct assets, then same-chain USDC/USDT/USDT0, then a NEAR asset or another registry asset. Native NEAR maps to wNEAR. FLEX minimum input is checked against the final aggregation minimum output, with bounded requotes.
|
|
89
|
+
|
|
90
|
+
`fundingSource: 'balance'` spends only the requested amount from an existing registered confidential balance, without a source transaction. `mode: 'TRANSFER'` requires the same funding and destination asset; otherwise mode defaults to `SWAP`. A batch has 1-10 unique recipients on one destination chain and asset. Randomized positive shares preserve the exact raw total with roughly 80-120 percent equal-share bounds, allowing integer rounding. Frozen random fractions are reused against the actual credited amount.
|
|
91
|
+
|
|
92
|
+
Supply `addressValidator` for BTC/Zcash or unsupported destination chains, using an established chain library. Known EVM, NEAR, Solana, Tron, Aptos and Sui address formats are checked by default. Case-sensitive addresses are never lowercased or silently truncated.
|
|
93
|
+
|
|
94
|
+
## Aggregation bridge
|
|
95
|
+
|
|
96
|
+
The optional `@rhea-finance/confidential-swap/aggregation` entry exposes `createAggregationFundingAdapter` and `HttpFundingReporter`. Install the optional peer `@rhea-finance/cross-chain-aggregation-dex@^2.0.6` when using its bridge/types.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { SwapClient } from '@rhea-finance/cross-chain-aggregation-dex';
|
|
100
|
+
import {
|
|
101
|
+
createAggregationFundingAdapter,
|
|
102
|
+
HttpFundingReporter,
|
|
103
|
+
} from '@rhea-finance/confidential-swap/aggregation';
|
|
104
|
+
|
|
105
|
+
const swapClient = new SwapClient({
|
|
106
|
+
baseUrl: indexerUrl,
|
|
107
|
+
apiKey: configuredApiToken,
|
|
108
|
+
reportMode: 'manual', // no duplicate automatic reports
|
|
109
|
+
executors: sourceChainExecutors,
|
|
110
|
+
});
|
|
111
|
+
const fundingSwapAdapter = createAggregationFundingAdapter({
|
|
112
|
+
client: swapClient,
|
|
113
|
+
reporter: new HttpFundingReporter({ baseUrl: indexerUrl, bearerToken: configuredApiToken }),
|
|
114
|
+
mapAsset: token => ({ chain: mapSwapChain(token), address: mapSwapAddress(token) }),
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Unlike the aggregation SDK's ordinary order query, advanced funding status uses `/api/swap/order-status?recordId=...`. The reporter sends `confidentiality: 'advanced'`. API credentials must be provided by the application, not copied from the reference repository.
|
|
119
|
+
|
|
120
|
+
## Intent protocol boundary
|
|
121
|
+
|
|
122
|
+
Withdrawal payloads are signed as returned by `/generate-intent`, matching the reference implementation. The SDK does not enforce a local transfer format or compare intent tokens and amounts against the quote. Signers, standards, nonces, deadlines and signatures are independently validated. NEP-413 withdrawal recipients are signed exactly as returned; authorization still requires the configured verifier. NEP-413 nonces accept Base64 or Base64URL and must decode to 32 bytes.
|
|
123
|
+
|
|
124
|
+
Applications may opt into additional protocol-specific validation using `verifyWithdrawIntent(data, context)`. Without this hook, generated intent effects are not locally validated. The hook does not bypass signer, standard, nonce, deadline or signature checks.
|
|
125
|
+
|
|
126
|
+
## Recovery and safety
|
|
127
|
+
|
|
128
|
+
Use `getExecution(id)` to inspect checkpoints and `resume(id)` to continue polling or signing. Reusing `execute(plan)` for a saved ID resumes it instead of sending another transfer. Default memory stores last only for the client lifetime; supply `ExecutionStore` and `SessionStore` for your own storage.
|
|
129
|
+
|
|
130
|
+
Checkpoints are saved **before** funding broadcast, report submission and withdrawal submission. A lost response leaves an `*_unknown` stage. Such writes are never automatically retried, including on 401. Supply read-only `reconcile`/`reconcileFunding` and `reconcileReport` lookups keyed by execution ID/transaction/deposit. An unknown batch is recovered only by finding the existing signer-scoped order with all saved withdrawal deposit addresses; a missing match remains unknown.
|
|
131
|
+
|
|
132
|
+
Timeout and abort stop local waiting, not the chain transaction. Keep the execution ID and resume. Submitted checkpoints can poll without connected wallets. Partial success is retained per recipient; terminal partial failures return `stage: 'failed'` with all available item statuses, never a blind retry.
|
|
133
|
+
|
|
134
|
+
`discardPrepared(id)` releases only a `created` checkpoint that has attempted no funds. After credited funds suffer price changes, `refreshWithdrawalReview(id)` generates and stores a new withdrawal preview/minimum; show the new review and then explicitly call `resume(id)`. It never repeats source funding.
|
|
135
|
+
|
|
136
|
+
Progress snapshots exclude session tokens and signed intent payloads, but include public quote/transaction metadata and addresses. Treat them as sensitive and trusted application data. The plan digest catches accidental edits, not malicious forgery. Do not accept arbitrary caller-created snapshots or mutate storage during execution.
|
|
137
|
+
|
|
138
|
+
Budget locks prevent concurrently running executions of the same identity/asset **within one client**. Stored unfinished executions do not block new executions and their checkpoints are retained. Multiple clients/processes sharing storage require an application-owned atomic/distributed lock; a plain async store is not a distributed lock. External balance changes can also affect confirmation; a balance check is not a cryptographic deposit attribution proof. Successful deposit status must provide actual `swapDetails.amountOut`; quoted output is not accepted as proof of funds.
|
|
139
|
+
|
|
140
|
+
NEAR named accounts may require an explicit public-key registration transaction on the linking chain. `createNearSigningAdapter` exposes a `registerPublicKey` callback and confirms registration. Implicit NEAR identities must match their Ed25519 key. Registration is not a source-chain funding transaction.
|
|
141
|
+
|
|
142
|
+
This is confidential-account orchestration, not a guarantee of end-to-end anonymity. Funding transactions, withdrawals, recipient reuse and backend reports can expose associations. Do not log tokens, full signed intents or wallet-provider errors.
|
|
143
|
+
|
|
144
|
+
## Verification status
|
|
145
|
+
|
|
146
|
+
Local tests exercise actual cryptographic signatures, the three-path/four-linking-kind matrix, source wallet separation, randomized integer bounds, HTTP fixtures, session recovery, ambiguous writes, partial statuses, price re-review and the published aggregation SDK client with mocked transport/execution. Packed ESM/CJS and consumer declarations are checked without React, wallet SDKs or the aggregation peer installed.
|
|
147
|
+
|
|
148
|
+
Signature domain implementations follow the primary [NEAR NEP-413 specification](https://github.com/near/NEPs/blob/master/neps/nep-0413.md) and [TronWeb message implementation](https://github.com/tronprotocol/tronweb/blob/master/src/utils/message.ts).
|
|
149
|
+
|
|
150
|
+
No real wallet signature, source funding transaction or npm publication is performed by tests. Live service checks are separate from fixture coverage. Before production use, verify the deployed intent format, POST withdrawal authorization, swap report schema, final status semantics, registry and fee policy in your environment; then perform explicitly approved small-value end-to-end tests.
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/adapters/index.ts
|
|
21
|
+
var adapters_exports = {};
|
|
22
|
+
__export(adapters_exports, {
|
|
23
|
+
createCheckedAdapter: () => createCheckedAdapter,
|
|
24
|
+
createEvmSigningAdapter: () => createEvmSigningAdapter,
|
|
25
|
+
createNearSigningAdapter: () => createNearSigningAdapter,
|
|
26
|
+
createSolanaSigningAdapter: () => createSolanaSigningAdapter,
|
|
27
|
+
createTronSigningAdapter: () => createTronSigningAdapter
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(adapters_exports);
|
|
30
|
+
var import_base4 = require("@scure/base");
|
|
31
|
+
|
|
32
|
+
// src/errors.ts
|
|
33
|
+
var ConfidentialSwapError = class extends Error {
|
|
34
|
+
constructor(code, message, status, executionId) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.code = code;
|
|
37
|
+
this.status = status;
|
|
38
|
+
this.executionId = executionId;
|
|
39
|
+
}
|
|
40
|
+
code;
|
|
41
|
+
status;
|
|
42
|
+
executionId;
|
|
43
|
+
name = "ConfidentialSwapError";
|
|
44
|
+
};
|
|
45
|
+
function assert(condition, message) {
|
|
46
|
+
if (!condition) throw new ConfidentialSwapError("INVALID_INPUT", message);
|
|
47
|
+
}
|
|
48
|
+
function responseAssert(condition, message) {
|
|
49
|
+
if (!condition) throw new ConfidentialSwapError("INVALID_RESPONSE", message);
|
|
50
|
+
}
|
|
51
|
+
function throwIfAborted(signal) {
|
|
52
|
+
if (signal?.aborted) throw new ConfidentialSwapError("ABORTED", "Local operation cancelled; submitted transactions are not cancelled.");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/identity.ts
|
|
56
|
+
var import_base = require("@scure/base");
|
|
57
|
+
var import_sha2562 = require("@noble/hashes/sha256");
|
|
58
|
+
|
|
59
|
+
// src/utils.ts
|
|
60
|
+
var import_sha256 = require("@noble/hashes/sha256");
|
|
61
|
+
var import_utils = require("@noble/hashes/utils");
|
|
62
|
+
function text(value, field) {
|
|
63
|
+
assert(typeof value === "string" && value.trim().length > 0, `${field} is required.`);
|
|
64
|
+
return value.trim();
|
|
65
|
+
}
|
|
66
|
+
function clone(value) {
|
|
67
|
+
return structuredClone(value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/identity.ts
|
|
71
|
+
function deriveConfidentialAccountId(kind, address) {
|
|
72
|
+
const account = text(address, "Wallet account");
|
|
73
|
+
if (kind === "near") {
|
|
74
|
+
assert(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(account) && account.length >= 2 && account.length <= 64, "Invalid NEAR account.");
|
|
75
|
+
return account;
|
|
76
|
+
}
|
|
77
|
+
if (kind === "evm") {
|
|
78
|
+
assert(/^0x[0-9a-f]{40}$/i.test(account), "Invalid EVM address.");
|
|
79
|
+
return account.toLowerCase();
|
|
80
|
+
}
|
|
81
|
+
if (kind === "solana") {
|
|
82
|
+
const bytes2 = import_base.base58.decode(account);
|
|
83
|
+
assert(bytes2.length === 32, "Invalid Solana public key.");
|
|
84
|
+
return import_base.base16.encode(bytes2).toLowerCase();
|
|
85
|
+
}
|
|
86
|
+
assert(kind === "tron", "Unsupported linking wallet kind.");
|
|
87
|
+
const bytes = (0, import_base.base58check)(import_sha2562.sha256).decode(account);
|
|
88
|
+
assert(bytes.length === 21 && bytes[0] === 65, "Invalid Tron address.");
|
|
89
|
+
return `0x${import_base.base16.encode(bytes.slice(1)).toLowerCase()}`;
|
|
90
|
+
}
|
|
91
|
+
function identityKey(identity) {
|
|
92
|
+
return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}:${identity.publicKey ?? ""}`;
|
|
93
|
+
}
|
|
94
|
+
function sameLinking(a, b) {
|
|
95
|
+
return identityKey(a) === identityKey(b);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/signatures.ts
|
|
99
|
+
var import_ed25519 = require("@noble/curves/ed25519");
|
|
100
|
+
var import_secp256k1 = require("@noble/curves/secp256k1");
|
|
101
|
+
var import_sha2563 = require("@noble/hashes/sha256");
|
|
102
|
+
var import_sha3 = require("@noble/hashes/sha3");
|
|
103
|
+
var import_utils3 = require("@noble/hashes/utils");
|
|
104
|
+
var import_base2 = require("@scure/base");
|
|
105
|
+
var encode = (s) => new TextEncoder().encode(s);
|
|
106
|
+
function u32(value) {
|
|
107
|
+
const b = new Uint8Array(4);
|
|
108
|
+
new DataView(b.buffer).setUint32(0, value, true);
|
|
109
|
+
return b;
|
|
110
|
+
}
|
|
111
|
+
function borshString(s) {
|
|
112
|
+
const b = encode(s);
|
|
113
|
+
return (0, import_utils3.concatBytes)(u32(b.length), b);
|
|
114
|
+
}
|
|
115
|
+
function decodeNep413Nonce(value) {
|
|
116
|
+
responseAssert(typeof value === "string", "Invalid NEP-413 nonce.");
|
|
117
|
+
const normalized = value.trim();
|
|
118
|
+
let nonce;
|
|
119
|
+
try {
|
|
120
|
+
nonce = import_base2.base64.decode(normalized);
|
|
121
|
+
} catch {
|
|
122
|
+
const unpadded = normalized.replace(/=+$/, "");
|
|
123
|
+
try {
|
|
124
|
+
nonce = import_base2.base64urlnopad.decode(unpadded);
|
|
125
|
+
} catch {
|
|
126
|
+
try {
|
|
127
|
+
nonce = import_base2.base64nopad.decode(unpadded);
|
|
128
|
+
} catch {
|
|
129
|
+
responseAssert(false, "Invalid NEP-413 nonce encoding.");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
responseAssert(nonce.length === 32, "The NEP-413 nonce must be 32 bytes.");
|
|
134
|
+
return nonce;
|
|
135
|
+
}
|
|
136
|
+
function nep413Hash(payload) {
|
|
137
|
+
const nonce = decodeNep413Nonce(payload.nonce);
|
|
138
|
+
return (0, import_sha2563.sha256)((0, import_utils3.concatBytes)(u32(2 ** 31 + 413), borshString(payload.message), nonce, borshString(payload.recipient), payload.callbackUrl === void 0 ? new Uint8Array([0]) : (0, import_utils3.concatBytes)(new Uint8Array([1]), borshString(payload.callbackUrl))));
|
|
139
|
+
}
|
|
140
|
+
function personalMessageHash(message, kind) {
|
|
141
|
+
const bytes = encode(message);
|
|
142
|
+
return (0, import_sha3.keccak_256)((0, import_utils3.concatBytes)(encode(`${kind === "evm" ? "Ethereum" : "TRON"} Signed Message:
|
|
143
|
+
${bytes.length}`), bytes));
|
|
144
|
+
}
|
|
145
|
+
function decodeEd25519(value, length) {
|
|
146
|
+
if (value instanceof Uint8Array) {
|
|
147
|
+
responseAssert(value.length === length, "Invalid Ed25519 byte length.");
|
|
148
|
+
return new Uint8Array(value);
|
|
149
|
+
}
|
|
150
|
+
const raw2 = value.replace(/^ed25519:/, "");
|
|
151
|
+
for (const decoder of [() => import_base2.base58.decode(raw2), () => import_base2.base64.decode(raw2), () => import_base2.base16.decode(raw2.replace(/^0x/, "").toUpperCase())]) {
|
|
152
|
+
try {
|
|
153
|
+
const b = decoder();
|
|
154
|
+
if (b.length === length) return b;
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
responseAssert(false, "Invalid Ed25519 encoding.");
|
|
159
|
+
}
|
|
160
|
+
function normalizeSecpSignature(value) {
|
|
161
|
+
const hex = value.replace(/^0x/i, "");
|
|
162
|
+
responseAssert(/^[0-9a-f]{130}$/i.test(hex), "Expected a 65-byte signature.");
|
|
163
|
+
const bytes = import_base2.base16.decode(hex.toUpperCase());
|
|
164
|
+
const v = bytes[64];
|
|
165
|
+
responseAssert([0, 1, 27, 28].includes(v), "Invalid recovery id.");
|
|
166
|
+
bytes[64] = v < 27 ? v + 27 : v;
|
|
167
|
+
return `0x${import_base2.base16.encode(bytes).toLowerCase()}`;
|
|
168
|
+
}
|
|
169
|
+
function verifyWalletSignature(data, identity) {
|
|
170
|
+
let valid = false;
|
|
171
|
+
try {
|
|
172
|
+
if (identity.kind === "near" && data.standard === "nep413") {
|
|
173
|
+
const key = decodeEd25519(identity.publicKey ?? "", 32);
|
|
174
|
+
valid = import_ed25519.ed25519.verify(decodeEd25519(data.signature, 64), nep413Hash(data.payload), key);
|
|
175
|
+
if (/^[0-9a-f]{64}$/.test(identity.accountId)) valid = valid && import_base2.base16.encode(key).toLowerCase() === identity.accountId;
|
|
176
|
+
} else if (identity.kind === "solana" && data.standard === "raw_ed25519") {
|
|
177
|
+
valid = import_ed25519.ed25519.verify(decodeEd25519(data.signature, 64), encode(data.payload), import_base2.base58.decode(identity.accountId));
|
|
178
|
+
} else if ((identity.kind === "evm" || identity.kind === "tron") && typeof data.payload === "string") {
|
|
179
|
+
const bytes = import_base2.base16.decode(normalizeSecpSignature(data.signature).slice(2).toUpperCase());
|
|
180
|
+
const sig = import_secp256k1.secp256k1.Signature.fromCompact(bytes.slice(0, 64)).addRecoveryBit(bytes[64] - 27);
|
|
181
|
+
const publicKey = sig.recoverPublicKey(personalMessageHash(data.payload, identity.kind)).toRawBytes(false);
|
|
182
|
+
const address = `0x${import_base2.base16.encode((0, import_sha3.keccak_256)(publicKey.slice(1)).slice(-20)).toLowerCase()}`;
|
|
183
|
+
valid = address === deriveConfidentialAccountId(identity.kind, identity.accountId);
|
|
184
|
+
}
|
|
185
|
+
} catch {
|
|
186
|
+
valid = false;
|
|
187
|
+
}
|
|
188
|
+
responseAssert(valid, "Signature does not verify against the frozen wallet identity.");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// src/validation.ts
|
|
192
|
+
var import_base3 = require("@scure/base");
|
|
193
|
+
function validateSigned(unsigned, signed, identity) {
|
|
194
|
+
responseAssert(signed.standard === unsigned.standard && JSON.stringify(signed.payload) === JSON.stringify(unsigned.payload), "Wallet changed the payload.");
|
|
195
|
+
text(signed.signature, "Signature");
|
|
196
|
+
if (identity.kind === "near" || identity.kind === "solana") {
|
|
197
|
+
const expected = identity.publicKey ?? (identity.kind === "solana" ? `ed25519:${identity.accountId}` : "");
|
|
198
|
+
responseAssert(expected && signed.public_key === expected, "Signing public key changed.");
|
|
199
|
+
}
|
|
200
|
+
verifyWalletSignature(signed, identity);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/adapters/index.ts
|
|
204
|
+
function createEvmSigningAdapter(getSigner) {
|
|
205
|
+
return createCheckedAdapter({
|
|
206
|
+
getIdentity: async () => ({ kind: "evm", accountId: await (await getSigner()).getAddress() }),
|
|
207
|
+
sign: async (data) => {
|
|
208
|
+
assert(data.standard === "erc191", "Expected ERC-191 payload.");
|
|
209
|
+
return { ...data, signature: normalizeSecpSignature(await (await getSigner()).signMessage(data.payload)) };
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
function createSolanaSigningAdapter(getWallet) {
|
|
214
|
+
return createCheckedAdapter({
|
|
215
|
+
getIdentity: async () => ({ kind: "solana", accountId: getWallet().publicKey.toBase58(), publicKey: `ed25519:${getWallet().publicKey.toBase58()}` }),
|
|
216
|
+
sign: async (data) => {
|
|
217
|
+
assert(data.standard === "raw_ed25519", "Expected raw Ed25519 payload.");
|
|
218
|
+
const wallet = getWallet();
|
|
219
|
+
const signature = await wallet.signMessage(new TextEncoder().encode(data.payload));
|
|
220
|
+
return { ...data, public_key: `ed25519:${wallet.publicKey.toBase58()}`, signature: `ed25519:${import_base4.base58.encode(decodeEd25519(signature, 64))}` };
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function createTronSigningAdapter(getWallet) {
|
|
225
|
+
return createCheckedAdapter({
|
|
226
|
+
getIdentity: async () => ({ kind: "tron", accountId: await getWallet().getAddress() }),
|
|
227
|
+
sign: async (data) => {
|
|
228
|
+
assert(data.standard === "tip191", "Expected TIP-191 payload.");
|
|
229
|
+
return { ...data, signature: normalizeSecpSignature(await getWallet().signMessageV2(data.payload)) };
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
function createNearSigningAdapter(wallet, api) {
|
|
234
|
+
const getIdentity = async () => {
|
|
235
|
+
const identity = await wallet.getIdentity();
|
|
236
|
+
return { kind: "near", accountId: identity.accountId, publicKey: `ed25519:${import_base4.base58.encode(decodeEd25519(identity.publicKey, 32))}` };
|
|
237
|
+
};
|
|
238
|
+
return createCheckedAdapter({
|
|
239
|
+
getIdentity,
|
|
240
|
+
prepare: async (signal) => {
|
|
241
|
+
const identity = await getIdentity();
|
|
242
|
+
if (/^[0-9a-f]{64}$/.test(identity.accountId)) {
|
|
243
|
+
const keyHex = Array.from(decodeEd25519(identity.publicKey, 32), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
244
|
+
assert(keyHex === identity.accountId, "Implicit NEAR account does not match its signing public key.");
|
|
245
|
+
} else {
|
|
246
|
+
const registered = await api.viewIntents("has_public_key", { account_id: identity.accountId, public_key: identity.publicKey }, signal);
|
|
247
|
+
responseAssert(typeof registered === "boolean", "Invalid key registration response.");
|
|
248
|
+
if (!registered) {
|
|
249
|
+
assert(wallet.registerPublicKey, "NEAR key registration requires an explicit registerPublicKey callback.");
|
|
250
|
+
throwIfAborted(signal);
|
|
251
|
+
await wallet.registerPublicKey(identity.accountId, identity.publicKey, api.intentsContract, signal);
|
|
252
|
+
responseAssert(await api.viewIntents("has_public_key", { account_id: identity.accountId, public_key: identity.publicKey }, signal) === true, "NEAR signing key registration is not confirmed.");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
sign: async (data) => {
|
|
257
|
+
assert(data.standard === "nep413", "Expected NEP-413 payload.");
|
|
258
|
+
const result = await wallet.signMessage({ ...data.payload, nonce: decodeNep413Nonce(data.payload.nonce) });
|
|
259
|
+
responseAssert(result.accountId === (await getIdentity()).accountId, "NEAR wallet returned a different account.");
|
|
260
|
+
return { ...data, public_key: `ed25519:${import_base4.base58.encode(decodeEd25519(result.publicKey, 32))}`, signature: `ed25519:${import_base4.base58.encode(decodeEd25519(result.signature, 64))}` };
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
function createCheckedAdapter(adapter) {
|
|
265
|
+
return {
|
|
266
|
+
getIdentity: () => adapter.getIdentity(),
|
|
267
|
+
prepare: adapter.prepare?.bind(adapter),
|
|
268
|
+
sign: async (data, signal) => {
|
|
269
|
+
throwIfAborted(signal);
|
|
270
|
+
const identity = await adapter.getIdentity();
|
|
271
|
+
const signed = await adapter.sign(clone(data), signal);
|
|
272
|
+
throwIfAborted(signal);
|
|
273
|
+
if (!sameLinking(identity, await adapter.getIdentity())) throw new ConfidentialSwapError("WALLET_CHANGED", "Wallet identity changed while signing.");
|
|
274
|
+
validateSigned(data, signed, identity);
|
|
275
|
+
return signed;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
280
|
+
0 && (module.exports = {
|
|
281
|
+
createCheckedAdapter,
|
|
282
|
+
createEvmSigningAdapter,
|
|
283
|
+
createNearSigningAdapter,
|
|
284
|
+
createSolanaSigningAdapter,
|
|
285
|
+
createTronSigningAdapter
|
|
286
|
+
});
|
|
287
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/index.ts","../../src/errors.ts","../../src/identity.ts","../../src/utils.ts","../../src/signatures.ts","../../src/validation.ts"],"sourcesContent":["import { base58 } from \"@scure/base\";\nimport { assert, ConfidentialSwapError, responseAssert, throwIfAborted } from \"../errors\";\nimport { sameLinking } from \"../identity\";\nimport { decodeEd25519, decodeNep413Nonce, normalizeSecpSignature } from \"../signatures\";\nimport { clone } from \"../utils\";\nimport { validateSigned } from \"../validation\";\nimport type { HttpConfidentialApi } from \"../api\";\nimport type { LinkingIdentity, SignedData, SigningAdapter, UnsignedData } from \"../types\";\n\nexport interface EvmMessageSigner { getAddress(): Promise<string>; signMessage(message: string): Promise<string> }\nexport function createEvmSigningAdapter(getSigner: () => Promise<EvmMessageSigner> | EvmMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"evm\", accountId: await (await getSigner()).getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"erc191\", \"Expected ERC-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await (await getSigner()).signMessage(data.payload)) };\n },\n });\n}\nexport interface SolanaMessageSigner { publicKey: { toBase58(): string }; signMessage(message: Uint8Array): Promise<Uint8Array> }\nexport function createSolanaSigningAdapter(getWallet: () => SolanaMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"solana\", accountId: getWallet().publicKey.toBase58(), publicKey: `ed25519:${getWallet().publicKey.toBase58()}` }),\n sign: async (data) => {\n assert(data.standard === \"raw_ed25519\", \"Expected raw Ed25519 payload.\");\n const wallet = getWallet();\n const signature = await wallet.signMessage(new TextEncoder().encode(data.payload));\n return { ...data, public_key: `ed25519:${wallet.publicKey.toBase58()}`, signature: `ed25519:${base58.encode(decodeEd25519(signature, 64))}` };\n },\n });\n}\nexport interface TronMessageSigner { getAddress(): Promise<string> | string; signMessageV2(message: string): Promise<string> }\nexport function createTronSigningAdapter(getWallet: () => TronMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"tron\", accountId: await getWallet().getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"tip191\", \"Expected TIP-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await getWallet().signMessageV2(data.payload)) };\n },\n });\n}\nexport interface NearMessageSigner {\n getIdentity(): Promise<{ accountId: string; publicKey: string }>;\n signMessage(params: { message: string; recipient: string; nonce: Uint8Array; callbackUrl?: string }): Promise<{ accountId: string; publicKey: string; signature: string }>;\n /** Explicit user-approved NEAR transaction: add_public_key on the configured Intents contract. */\n registerPublicKey?(accountId: string, publicKey: string, contract: string, signal?: AbortSignal): Promise<void>;\n}\nexport function createNearSigningAdapter(wallet: NearMessageSigner, api: Pick<HttpConfidentialApi, \"viewIntents\" | \"intentsContract\">): SigningAdapter {\n const getIdentity = async (): Promise<LinkingIdentity> => {\n const identity = await wallet.getIdentity();\n return { kind: \"near\", accountId: identity.accountId, publicKey: `ed25519:${base58.encode(decodeEd25519(identity.publicKey, 32))}` };\n };\n return createCheckedAdapter({\n getIdentity,\n prepare: async (signal) => {\n const identity = await getIdentity();\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) {\n const keyHex = Array.from(decodeEd25519(identity.publicKey!, 32), (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n assert(keyHex === identity.accountId, \"Implicit NEAR account does not match its signing public key.\");\n } else {\n const registered = await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal);\n responseAssert(typeof registered === \"boolean\", \"Invalid key registration response.\");\n if (!registered) {\n assert(wallet.registerPublicKey, \"NEAR key registration requires an explicit registerPublicKey callback.\");\n throwIfAborted(signal);\n await wallet.registerPublicKey(identity.accountId, identity.publicKey!, api.intentsContract, signal);\n responseAssert(await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal) === true, \"NEAR signing key registration is not confirmed.\");\n }\n }\n },\n sign: async (data) => {\n assert(data.standard === \"nep413\", \"Expected NEP-413 payload.\");\n const result = await wallet.signMessage({ ...data.payload, nonce: decodeNep413Nonce(data.payload.nonce) });\n responseAssert(result.accountId === (await getIdentity()).accountId, \"NEAR wallet returned a different account.\");\n return { ...data, public_key: `ed25519:${base58.encode(decodeEd25519(result.publicKey, 32))}`, signature: `ed25519:${base58.encode(decodeEd25519(result.signature, 64))}` };\n },\n });\n}\nexport function createCheckedAdapter(adapter: SigningAdapter): SigningAdapter {\n return {\n getIdentity: () => adapter.getIdentity(),\n prepare: adapter.prepare?.bind(adapter),\n sign: async (data: UnsignedData, signal?: AbortSignal): Promise<SignedData> => {\n throwIfAborted(signal);\n const identity = await adapter.getIdentity();\n const signed = await adapter.sign(clone(data), signal);\n throwIfAborted(signal);\n if (!sameLinking(identity, await adapter.getIdentity())) throw new ConfidentialSwapError(\"WALLET_CHANGED\", \"Wallet identity changed while signing.\");\n validateSigned(data, signed, identity);\n return signed;\n },\n };\n}\n","export type ErrorCode =\n | \"INVALID_INPUT\" | \"INVALID_RESPONSE\" | \"HTTP_ERROR\" | \"UNAUTHORIZED\"\n | \"WALLET_CHANGED\" | \"MISSING_WALLET\" | \"QUOTE_EXPIRED\" | \"BUSY\"\n | \"CONFIRMATION_REQUIRED\" | \"TIMEOUT\" | \"ABORTED\" | \"TERMINAL_FAILURE\";\n\nexport class ConfidentialSwapError extends Error {\n readonly name = \"ConfidentialSwapError\";\n constructor(\n readonly code: ErrorCode,\n message: string,\n readonly status?: number,\n readonly executionId?: string,\n ) { super(message); }\n}\n\nexport function assert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_INPUT\", message);\n}\n\nexport function responseAssert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_RESPONSE\", message);\n}\n\nexport function throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) throw new ConfidentialSwapError(\"ABORTED\", \"Local operation cancelled; submitted transactions are not cancelled.\");\n}\n","import { base16, base58, base58check } from \"@scure/base\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { assert } from \"./errors\";\nimport { text } from \"./utils\";\nimport type { FundingIdentity, LinkingIdentity, LinkingKind, SigningStandard } from \"./types\";\n\nexport const CONFIDENTIAL_LINKING_KINDS = [\"near\", \"evm\", \"solana\", \"tron\"] as const;\nexport const standards: Record<LinkingKind, SigningStandard> = { near: \"nep413\", evm: \"erc191\", solana: \"raw_ed25519\", tron: \"tip191\" };\nexport function deriveConfidentialAccountId(kind: LinkingKind, address: string): string {\n const account = text(address, \"Wallet account\");\n if (kind === \"near\") {\n assert(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(account) && account.length >= 2 && account.length <= 64, \"Invalid NEAR account.\");\n return account;\n }\n if (kind === \"evm\") { assert(/^0x[0-9a-f]{40}$/i.test(account), \"Invalid EVM address.\"); return account.toLowerCase(); }\n if (kind === \"solana\") {\n const bytes = base58.decode(account);\n assert(bytes.length === 32, \"Invalid Solana public key.\");\n return base16.encode(bytes).toLowerCase();\n }\n assert(kind === \"tron\", \"Unsupported linking wallet kind.\");\n const bytes = base58check(sha256).decode(account);\n assert(bytes.length === 21 && bytes[0] === 0x41, \"Invalid Tron address.\");\n return `0x${base16.encode(bytes.slice(1)).toLowerCase()}`;\n}\nexport function identityKey(identity: LinkingIdentity): string {\n return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}:${identity.publicKey ?? \"\"}`;\n}\nexport function sameLinking(a: LinkingIdentity, b: LinkingIdentity): boolean { return identityKey(a) === identityKey(b); }\nexport function sameFunding(a: FundingIdentity, b: FundingIdentity): boolean {\n return a.kind === b.kind && a.chain === b.chain && (a.kind === \"evm\" ? a.accountId.toLowerCase() === b.accountId.toLowerCase() : a.accountId === b.accountId);\n}\nexport function resolveLinkingWallet(input: { sourceKind?: string; wallets: readonly LinkingIdentity[]; preferred?: LinkingIdentity }): LinkingIdentity | null {\n const wallets = input.wallets.filter((w) => CONFIDENTIAL_LINKING_KINDS.includes(w.kind) && w.accountId.trim());\n if (input.preferred) return wallets.find((w) => sameLinking(w, input.preferred!)) ?? null;\n return wallets.find((w) => w.kind === input.sourceKind) ?? CONFIDENTIAL_LINKING_KINDS.map((kind) => wallets.find((w) => w.kind === kind)).find(Boolean) ?? null;\n}\n","import { sha256 } from \"@noble/hashes/sha256\";\nimport { bytesToHex } from \"@noble/hashes/utils\";\nimport { assert, throwIfAborted } from \"./errors\";\nimport type { Balance, QuotePlan } from \"./types\";\n\nexport function raw(value: unknown, field = \"Amount\", allowZero = false): bigint {\n assert(typeof value === \"string\" && /^(0|[1-9]\\d*)$/.test(value), `${field} must be a canonical integer string.`);\n const result = BigInt(value);\n assert(allowZero || result > 0n, `${field} must be positive.`);\n return result;\n}\nexport function text(value: unknown, field: string): string {\n assert(typeof value === \"string\" && value.trim().length > 0, `${field} is required.`);\n return value.trim();\n}\nexport function clone<T>(value: T): T { return structuredClone(value); }\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.entries(value).filter(([, v]) => v !== undefined).sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${JSON.stringify(k)}:${canonical(v)}`).join(\",\")}}`;\n }\n assert(value === null || [\"string\", \"boolean\", \"number\"].includes(typeof value), \"Plan data must be JSON-serializable.\");\n if (typeof value === \"number\") assert(Number.isFinite(value), \"Plan numbers must be finite.\");\n return JSON.stringify(value);\n}\nexport function planDigest(plan: Omit<QuotePlan, \"digest\"> | QuotePlan): string {\n const { digest: _digest, ...body } = plan as QuotePlan;\n return bytesToHex(sha256(new TextEncoder().encode(canonical(body))));\n}\nexport function randomFraction(): number {\n return crypto.getRandomValues(new Uint32Array(1))[0]! / 0xffffffff;\n}\nexport function splitConfidentialRawAmount(totalRaw: string, count: number, values?: readonly number[]): string[] {\n assert(Number.isInteger(count) && count >= 1 && count <= 10, \"A batch requires 1 to 10 recipients.\");\n const total = raw(totalRaw);\n assert(total >= BigInt(count), \"Amount too small for every recipient.\");\n const minimum = total * 80n / (100n * BigInt(count));\n const lowBound = minimum > 0n ? minimum : 1n;\n const denominator = 100n * BigInt(count);\n const maximum = (total * 120n + denominator - 1n) / denominator;\n const highBound = maximum > lowBound ? maximum : lowBound;\n const shares: bigint[] = [];\n let remaining = total;\n for (let i = 0; i < count - 1; i++) {\n const left = BigInt(count - i - 1);\n const low = remaining - highBound * left > lowBound ? remaining - highBound * left : lowBound;\n const high = remaining - lowBound * left < highBound ? remaining - lowBound * left : highBound;\n assert(low <= high, \"Amount cannot be split safely.\");\n const fraction = values?.[i] ?? randomFraction();\n assert(Number.isFinite(fraction) && fraction >= 0 && fraction <= 1, \"Random fractions must be within [0, 1].\");\n const share = low + (high - low) * BigInt(Math.floor(fraction * 1_000_000)) / 1_000_000n;\n shares.push(share);\n remaining -= share;\n }\n assert(remaining >= lowBound && remaining <= highBound, \"Final share outside safe bounds.\");\n return [...shares, remaining].map(String);\n}\nexport function availableForAsset(balances: readonly Balance[], assetId: string): string {\n const exact = balances.find((b) => b.tokenId === assetId);\n const entry = exact ?? balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${assetId}`));\n return raw(entry?.available ?? \"0\", \"Available balance\", true).toString();\n}\nexport async function delay(ms: number, signal?: AbortSignal): Promise<void> {\n throwIfAborted(signal);\n await new Promise<void>((resolve, reject) => {\n const finish = () => { signal?.removeEventListener(\"abort\", abort); resolve(); };\n const timer = setTimeout(finish, ms);\n const abort = () => { clearTimeout(timer); signal?.removeEventListener(\"abort\", abort); try { throwIfAborted(signal); } catch (e) { reject(e); } };\n signal?.addEventListener(\"abort\", abort, { once: true });\n });\n}\n","import { ed25519 } from \"@noble/curves/ed25519\";\nimport { secp256k1 } from \"@noble/curves/secp256k1\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { keccak_256 } from \"@noble/hashes/sha3\";\nimport { concatBytes } from \"@noble/hashes/utils\";\nimport { base16, base58, base64, base64nopad, base64urlnopad } from \"@scure/base\";\nimport { responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId } from \"./identity\";\nimport type { LinkingIdentity, SignedData, UnsignedData } from \"./types\";\n\nconst encode = (s: string) => new TextEncoder().encode(s);\nfunction u32(value: number): Uint8Array { const b = new Uint8Array(4); new DataView(b.buffer).setUint32(0, value, true); return b; }\nfunction borshString(s: string): Uint8Array { const b = encode(s); return concatBytes(u32(b.length), b); }\nexport function decodeNep413Nonce(value: string): Uint8Array {\n responseAssert(typeof value === \"string\", \"Invalid NEP-413 nonce.\");\n const normalized = value.trim();\n let nonce: Uint8Array;\n try { nonce = base64.decode(normalized); }\n catch {\n const unpadded = normalized.replace(/=+$/, \"\");\n try { nonce = base64urlnopad.decode(unpadded); }\n catch {\n try { nonce = base64nopad.decode(unpadded); }\n catch { responseAssert(false, \"Invalid NEP-413 nonce encoding.\"); }\n }\n }\n responseAssert(nonce.length === 32, \"The NEP-413 nonce must be 32 bytes.\");\n return nonce;\n}\nexport function nep413Hash(payload: Extract<UnsignedData, { standard: \"nep413\" }>[\"payload\"]): Uint8Array {\n const nonce = decodeNep413Nonce(payload.nonce);\n return sha256(concatBytes(u32(2 ** 31 + 413), borshString(payload.message), nonce, borshString(payload.recipient), payload.callbackUrl === undefined ? new Uint8Array([0]) : concatBytes(new Uint8Array([1]), borshString(payload.callbackUrl))));\n}\nexport function personalMessageHash(message: string, kind: \"evm\" | \"tron\"): Uint8Array {\n const bytes = encode(message);\n return keccak_256(concatBytes(encode(`\\x19${kind === \"evm\" ? \"Ethereum\" : \"TRON\"} Signed Message:\\n${bytes.length}`), bytes));\n}\nexport function decodeEd25519(value: string | Uint8Array, length: number): Uint8Array {\n if (value instanceof Uint8Array) { responseAssert(value.length === length, \"Invalid Ed25519 byte length.\"); return new Uint8Array(value); }\n const raw = value.replace(/^ed25519:/, \"\");\n for (const decoder of [() => base58.decode(raw), () => base64.decode(raw), () => base16.decode(raw.replace(/^0x/, \"\").toUpperCase())]) {\n try { const b = decoder(); if (b.length === length) return b; } catch { /* Wallets use base58, base64, or hex. */ }\n }\n responseAssert(false, \"Invalid Ed25519 encoding.\");\n}\nexport function normalizeSecpSignature(value: string): string {\n const hex = value.replace(/^0x/i, \"\");\n responseAssert(/^[0-9a-f]{130}$/i.test(hex), \"Expected a 65-byte signature.\");\n const bytes = base16.decode(hex.toUpperCase());\n const v = bytes[64]!;\n responseAssert([0, 1, 27, 28].includes(v), \"Invalid recovery id.\");\n bytes[64] = v < 27 ? v + 27 : v;\n return `0x${base16.encode(bytes).toLowerCase()}`;\n}\nexport function verifyWalletSignature(data: SignedData, identity: LinkingIdentity): void {\n let valid = false;\n try {\n if (identity.kind === \"near\" && data.standard === \"nep413\") {\n const key = decodeEd25519(identity.publicKey ?? \"\", 32);\n valid = ed25519.verify(decodeEd25519(data.signature, 64), nep413Hash(data.payload), key);\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) valid = valid && base16.encode(key).toLowerCase() === identity.accountId;\n } else if (identity.kind === \"solana\" && data.standard === \"raw_ed25519\") {\n valid = ed25519.verify(decodeEd25519(data.signature, 64), encode(data.payload), base58.decode(identity.accountId));\n } else if ((identity.kind === \"evm\" || identity.kind === \"tron\") && typeof data.payload === \"string\") {\n const bytes = base16.decode(normalizeSecpSignature(data.signature).slice(2).toUpperCase());\n const sig = secp256k1.Signature.fromCompact(bytes.slice(0, 64)).addRecoveryBit(bytes[64]! - 27);\n const publicKey = sig.recoverPublicKey(personalMessageHash(data.payload, identity.kind)).toRawBytes(false);\n const address = `0x${base16.encode(keccak_256(publicKey.slice(1)).slice(-20)).toLowerCase()}`;\n valid = address === deriveConfidentialAccountId(identity.kind, identity.accountId);\n }\n } catch { valid = false; }\n responseAssert(valid, \"Signature does not verify against the frozen wallet identity.\");\n}\n","import { base58, base64 } from \"@scure/base\";\nimport { assert, responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId, standards } from \"./identity\";\nimport { normalizeChain } from \"./routing\";\nimport { raw, text } from \"./utils\";\nimport { decodeNep413Nonce, verifyWalletSignature } from \"./signatures\";\nimport type { LinkingIdentity, QuoteResponse, SignedData, Token, UnsignedData } from \"./types\";\n\nconst evmChains = new Set([\"eth\", \"arb\", \"avax\", \"op\", \"pol\", \"bsc\", \"base\", \"gnosis\", \"aurora\", \"bera\", \"berachain\", \"monad\", \"hypercore\", \"hyperliquid\", \"linea\", \"scroll\", \"zksync\", \"mantle\", \"celo\", \"sonic\"]);\nexport type AddressValidator = (address: string, token: Token) => boolean;\nexport function validateRecipients(addresses: readonly string[], token: Token, custom?: AddressValidator): string[] {\n assert(addresses.length >= 1 && addresses.length <= 10, \"A batch requires 1 to 10 recipients.\");\n const chain = normalizeChain(token.blockchain);\n const evm = evmChains.has(chain) || /^\\d+$/.test(token.swapChain ?? chain);\n const seen = new Set<string>();\n return addresses.map((value) => {\n const address = text(value, \"Recipient address\");\n let valid = false;\n try {\n if (custom) valid = custom(address, token);\n else if (evm) valid = /^0x[0-9a-f]{40}$/i.test(address);\n else if (chain === \"near\") { deriveConfidentialAccountId(\"near\", address); valid = true; }\n else if (chain === \"sol\") valid = base58.decode(address).length === 32;\n else if (chain === \"tron\") { deriveConfidentialAccountId(\"tron\", address); valid = true; }\n else if (chain === \"aptos\") valid = /^0x[0-9a-f]{1,64}$/i.test(address);\n else if (chain === \"sui\") valid = /^0x[0-9a-f]{64}$/i.test(address);\n else assert(false, \"Supply an address validator for this destination chain (including BTC/Zcash).\");\n } catch (error) { if (!custom && !evm && ![\"near\", \"sol\", \"tron\", \"aptos\", \"sui\"].includes(chain)) throw error; }\n assert(valid, \"Invalid recipient address for the destination chain.\");\n const key = evm || [\"aptos\", \"sui\"].includes(chain) ? address.toLowerCase() : address;\n assert(!seen.has(key), \"Duplicate recipient address.\");\n seen.add(key);\n return address;\n });\n}\nexport function validateToken(token: Token): void {\n text(token.assetId, \"Asset id\"); text(token.blockchain, \"Blockchain\"); text(token.symbol, \"Symbol\");\n assert(Number.isInteger(token.decimals) && token.decimals >= 0 && token.decimals <= 255, \"Invalid token decimals.\");\n}\nexport function validateQuote(q: QuoteResponse, requireDeposit: boolean): void {\n responseAssert(q && typeof q.quote === \"object\" && q.quote, \"Missing quote.\");\n raw(q.quote.amountIn, \"Quoted input\"); raw(q.quote.amountOut, \"Quoted output\");\n if (q.quote.minAmountOut !== undefined) assert(raw(q.quote.minAmountOut) <= raw(q.quote.amountOut), \"Minimum output exceeds quoted output.\");\n if (q.quote.minAmountIn !== undefined) raw(q.quote.minAmountIn);\n if (requireDeposit) text(q.quote.depositAddress, \"Deposit address\");\n}\nexport function payloadMessage(data: UnsignedData): Record<string, unknown> {\n let message: unknown;\n try { message = JSON.parse(typeof data.payload === \"string\" ? data.payload : data.payload.message); }\n catch { responseAssert(false, \"Invalid intent JSON.\"); }\n responseAssert(message && typeof message === \"object\" && !Array.isArray(message), \"Invalid intent payload.\");\n return message as Record<string, unknown>;\n}\nexport function validatePayload(data: UnsignedData, identity: LinkingIdentity, signerId: string, contract: string, now: number, purpose: \"authorization\" | \"withdrawal\" = \"authorization\"): Record<string, unknown> {\n responseAssert(data.standard === standards[identity.kind], \"Signing standard does not match wallet.\");\n const msg = payloadMessage(data);\n responseAssert(msg.signer_id === signerId, \"Intent signer does not match the frozen identity.\");\n const deadline = Date.parse(String(msg.deadline ?? \"\"));\n responseAssert(Number.isFinite(deadline) && deadline > now, \"Intent deadline expired or invalid.\");\n responseAssert(Array.isArray(msg.intents), \"Intent list is missing.\");\n if (data.standard === \"nep413\") {\n text(data.payload.recipient, \"NEP-413 recipient\");\n // Generated withdrawals carry their own signed recipient; only login binds the configured verifier.\n if (purpose === \"authorization\") responseAssert(data.payload.recipient === contract, \"Invalid NEP-413 authorization verifier.\");\n decodeNep413Nonce(data.payload.nonce);\n } else {\n responseAssert(msg.verifying_contract === contract && typeof msg.nonce === \"string\" && base64.decode(msg.nonce).length === 32, \"Invalid verifier or nonce.\");\n }\n return msg;\n}\nexport function validateSigned(unsigned: UnsignedData, signed: SignedData, identity: LinkingIdentity): void {\n responseAssert(signed.standard === unsigned.standard && JSON.stringify(signed.payload) === JSON.stringify(unsigned.payload), \"Wallet changed the payload.\");\n text(signed.signature, \"Signature\");\n if (identity.kind === \"near\" || identity.kind === \"solana\") {\n const expected = identity.publicKey ?? (identity.kind === \"solana\" ? `ed25519:${identity.accountId}` : \"\");\n responseAssert(expected && signed.public_key === expected, \"Signing public key changed.\");\n }\n verifyWalletSignature(signed, identity);\n}\n"],"mappings":"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","names":["import_base","import_sha256","bytes","import_sha256","import_utils","import_base","raw","import_base"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { H as HttpConfidentialApi } from '../api-DenG9sWp.cjs';
|
|
2
|
+
import { S as SigningAdapter } from '../types-Bq8OZRUK.cjs';
|
|
3
|
+
|
|
4
|
+
interface EvmMessageSigner {
|
|
5
|
+
getAddress(): Promise<string>;
|
|
6
|
+
signMessage(message: string): Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
declare function createEvmSigningAdapter(getSigner: () => Promise<EvmMessageSigner> | EvmMessageSigner): SigningAdapter;
|
|
9
|
+
interface SolanaMessageSigner {
|
|
10
|
+
publicKey: {
|
|
11
|
+
toBase58(): string;
|
|
12
|
+
};
|
|
13
|
+
signMessage(message: Uint8Array): Promise<Uint8Array>;
|
|
14
|
+
}
|
|
15
|
+
declare function createSolanaSigningAdapter(getWallet: () => SolanaMessageSigner): SigningAdapter;
|
|
16
|
+
interface TronMessageSigner {
|
|
17
|
+
getAddress(): Promise<string> | string;
|
|
18
|
+
signMessageV2(message: string): Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
declare function createTronSigningAdapter(getWallet: () => TronMessageSigner): SigningAdapter;
|
|
21
|
+
interface NearMessageSigner {
|
|
22
|
+
getIdentity(): Promise<{
|
|
23
|
+
accountId: string;
|
|
24
|
+
publicKey: string;
|
|
25
|
+
}>;
|
|
26
|
+
signMessage(params: {
|
|
27
|
+
message: string;
|
|
28
|
+
recipient: string;
|
|
29
|
+
nonce: Uint8Array;
|
|
30
|
+
callbackUrl?: string;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
accountId: string;
|
|
33
|
+
publicKey: string;
|
|
34
|
+
signature: string;
|
|
35
|
+
}>;
|
|
36
|
+
/** Explicit user-approved NEAR transaction: add_public_key on the configured Intents contract. */
|
|
37
|
+
registerPublicKey?(accountId: string, publicKey: string, contract: string, signal?: AbortSignal): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
declare function createNearSigningAdapter(wallet: NearMessageSigner, api: Pick<HttpConfidentialApi, "viewIntents" | "intentsContract">): SigningAdapter;
|
|
40
|
+
declare function createCheckedAdapter(adapter: SigningAdapter): SigningAdapter;
|
|
41
|
+
|
|
42
|
+
export { type EvmMessageSigner, type NearMessageSigner, type SolanaMessageSigner, type TronMessageSigner, createCheckedAdapter, createEvmSigningAdapter, createNearSigningAdapter, createSolanaSigningAdapter, createTronSigningAdapter };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { H as HttpConfidentialApi } from '../api-cazA5IdP.js';
|
|
2
|
+
import { S as SigningAdapter } from '../types-Bq8OZRUK.js';
|
|
3
|
+
|
|
4
|
+
interface EvmMessageSigner {
|
|
5
|
+
getAddress(): Promise<string>;
|
|
6
|
+
signMessage(message: string): Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
declare function createEvmSigningAdapter(getSigner: () => Promise<EvmMessageSigner> | EvmMessageSigner): SigningAdapter;
|
|
9
|
+
interface SolanaMessageSigner {
|
|
10
|
+
publicKey: {
|
|
11
|
+
toBase58(): string;
|
|
12
|
+
};
|
|
13
|
+
signMessage(message: Uint8Array): Promise<Uint8Array>;
|
|
14
|
+
}
|
|
15
|
+
declare function createSolanaSigningAdapter(getWallet: () => SolanaMessageSigner): SigningAdapter;
|
|
16
|
+
interface TronMessageSigner {
|
|
17
|
+
getAddress(): Promise<string> | string;
|
|
18
|
+
signMessageV2(message: string): Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
declare function createTronSigningAdapter(getWallet: () => TronMessageSigner): SigningAdapter;
|
|
21
|
+
interface NearMessageSigner {
|
|
22
|
+
getIdentity(): Promise<{
|
|
23
|
+
accountId: string;
|
|
24
|
+
publicKey: string;
|
|
25
|
+
}>;
|
|
26
|
+
signMessage(params: {
|
|
27
|
+
message: string;
|
|
28
|
+
recipient: string;
|
|
29
|
+
nonce: Uint8Array;
|
|
30
|
+
callbackUrl?: string;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
accountId: string;
|
|
33
|
+
publicKey: string;
|
|
34
|
+
signature: string;
|
|
35
|
+
}>;
|
|
36
|
+
/** Explicit user-approved NEAR transaction: add_public_key on the configured Intents contract. */
|
|
37
|
+
registerPublicKey?(accountId: string, publicKey: string, contract: string, signal?: AbortSignal): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
declare function createNearSigningAdapter(wallet: NearMessageSigner, api: Pick<HttpConfidentialApi, "viewIntents" | "intentsContract">): SigningAdapter;
|
|
40
|
+
declare function createCheckedAdapter(adapter: SigningAdapter): SigningAdapter;
|
|
41
|
+
|
|
42
|
+
export { type EvmMessageSigner, type NearMessageSigner, type SolanaMessageSigner, type TronMessageSigner, createCheckedAdapter, createEvmSigningAdapter, createNearSigningAdapter, createSolanaSigningAdapter, createTronSigningAdapter };
|