@anywalletkit/extension-kit 0.3.5 → 0.4.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 +28 -7
- package/dist/index.cjs +859 -183
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +484 -69
- package/dist/index.d.ts +484 -69
- package/dist/index.js +862 -174
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { KeyringStorage, SecretStorage } from '@anywalletkit/keyring';
|
|
2
|
-
import { Quote, Swap2ExecutionPlan, CrossChainProvider,
|
|
2
|
+
import { Quote, QuoteParams, Swap2ExecutionPlan, CrossChainProvider, IntentStatus } from '@anywalletkit/protocol-swap2-core';
|
|
3
|
+
import { TonSignDataPayload } from '@anywalletkit/wallet-ton/tonconnect';
|
|
4
|
+
export { TONCONNECT_ERRORS, TONCONNECT_MAX_MESSAGES, TONCONNECT_NETWORKS, TONCONNECT_SIGN_DATA_MAX, TonConnectError, TonConnectMessage, TonConnectParseOptions, TonConnectRequest, TonConnectSendOptions, TonConnectSendTransaction, TonSignDataPayload, parseConnectRequest, parseSendTransaction, parseSignData, sameTonConnectAddress, tonConnectFriendlyAddress, tonConnectRawAddress } from '@anywalletkit/wallet-ton/tonconnect';
|
|
3
5
|
|
|
4
6
|
/** A vault or session rule was broken. Messages are safe to show the user and never contain secrets. */
|
|
5
7
|
declare class VaultError extends Error {
|
|
@@ -176,6 +178,14 @@ declare class Vault {
|
|
|
176
178
|
*/
|
|
177
179
|
unlock(password: string): Promise<Uint8Array>;
|
|
178
180
|
private _unlock;
|
|
181
|
+
/**
|
|
182
|
+
* A DEK unwrapped from a dek / passkey box must be the key this vault's secrets are sealed under
|
|
183
|
+
* (audit 2026-11-09 E21): a box spliced in from another vault, under another password or passkey,
|
|
184
|
+
* opens with that password but holds a foreign key. Proven with the DEK check, or — in an envelope
|
|
185
|
+
* written before it — the first secret; an old empty envelope has nothing to prove it with. Returns
|
|
186
|
+
* `dek`; on a mismatch zeroizes it and fails as `wrong-password` (the same failure as tampering).
|
|
187
|
+
*/
|
|
188
|
+
private _proveOwn;
|
|
179
189
|
/**
|
|
180
190
|
* Re-wrap the DEK under a new password (fresh salt, current KDF). Secrets and passkeys are untouched —
|
|
181
191
|
* and so is the DEK: after a suspected compromise (a copied profile, a leaked session, a lost passkey)
|
|
@@ -192,8 +202,11 @@ declare class Vault {
|
|
|
192
202
|
*
|
|
193
203
|
* Passkeys are dropped — their boxes hold the old DEK and cannot be re-wrapped without their PRF
|
|
194
204
|
* output — and must be registered again ({@link Vault.addPasskey} with the new DEK).
|
|
205
|
+
*
|
|
206
|
+
* With `newPassword` this is also the password change: the new DEK is wrapped under `newPassword`
|
|
207
|
+
* (at least {@link VAULT_MIN_PASSWORD_LENGTH} characters), and `password` must be the current one.
|
|
195
208
|
*/
|
|
196
|
-
rotateVaultKey(password: string): Promise<Uint8Array>;
|
|
209
|
+
rotateVaultKey(password: string, newPassword?: string): Promise<Uint8Array>;
|
|
197
210
|
/** Public view of the registered passkeys (ids, labels; whether each can verify assertions). */
|
|
198
211
|
listPasskeys(): Promise<Array<{
|
|
199
212
|
id: string;
|
|
@@ -319,10 +332,20 @@ declare class Session {
|
|
|
319
332
|
* a missed alarm cannot keep the key alive.
|
|
320
333
|
*/
|
|
321
334
|
getKey(): Promise<Uint8Array>;
|
|
322
|
-
/**
|
|
335
|
+
/**
|
|
336
|
+
* User activity: push the auto-lock out again. No-op when locked. Call it for explicit user
|
|
337
|
+
* gestures only (unlock, send, approve / decline, an action in the wallet's own UI) — not for
|
|
338
|
+
* passive polls, page requests or worker restarts, or the timer never runs out.
|
|
339
|
+
*/
|
|
323
340
|
touch(): Promise<void>;
|
|
324
341
|
get autoLockMs(): number;
|
|
325
|
-
/**
|
|
342
|
+
/**
|
|
343
|
+
* Set the timer period (0 disables). Never pushes the deadline out — call this at every worker
|
|
344
|
+
* start with the stored setting: it re-arms the alarm at the stored deadline (a restart must not
|
|
345
|
+
* count as activity, audit 2026-11-09 E11), and only brings the deadline forward when the new
|
|
346
|
+
* period ends sooner. A longer period (or 0) applies from the next {@link Session.touch} /
|
|
347
|
+
* {@link Session.unlock}; call `touch()` right after when the user changed it explicitly.
|
|
348
|
+
*/
|
|
326
349
|
setAutoLockMs(ms: number): Promise<void>;
|
|
327
350
|
onLock(callback: () => void): () => void;
|
|
328
351
|
private _serial;
|
|
@@ -585,6 +608,11 @@ declare class NetworksTable {
|
|
|
585
608
|
/** Cache first (readers see it at once), rolled back when storage refuses. */
|
|
586
609
|
private write;
|
|
587
610
|
private custom;
|
|
611
|
+
/**
|
|
612
|
+
* Forget the cached table: the next read asks storage again. For a storage whose answer changes under
|
|
613
|
+
* the table — e.g. one that only hands out the user's networks once the wallet is unlocked.
|
|
614
|
+
*/
|
|
615
|
+
reload(): Promise<void>;
|
|
588
616
|
}
|
|
589
617
|
/**
|
|
590
618
|
* EIP-3085 `wallet_addEthereumChain` parameter → {@link EvmNetwork}, or the error
|
|
@@ -662,12 +690,23 @@ declare class PermissionStore {
|
|
|
662
690
|
get(origin: string): Promise<OriginPermission | null>;
|
|
663
691
|
list(): Promise<OriginPermission[]>;
|
|
664
692
|
connect(origin: string, accounts: string[], chain: string): Promise<OriginPermission>;
|
|
693
|
+
/**
|
|
694
|
+
* Add EVM accounts to an origin's grant (per-site grants): the new ones first, the ones it already
|
|
695
|
+
* holds stay. The chain stays the origin's own when it has one. Used by the router's connect; `connect`
|
|
696
|
+
* replaces the list instead.
|
|
697
|
+
*/
|
|
698
|
+
grant(origin: string, accounts: string[], chain: string): Promise<OriginPermission>;
|
|
665
699
|
/** Connect another chain's accounts to the same origin (one "connected sites" list). */
|
|
666
700
|
connectChain(origin: string, key: ChainAccountsKey, accounts: string[], defaultChain: string): Promise<OriginPermission>;
|
|
667
701
|
/** Drop one chain's accounts; the origin stays connected while any chain remains. A no-op (no write) when there is nothing to drop. */
|
|
668
702
|
disconnectChain(origin: string, key: 'accounts' | ChainAccountsKey): Promise<void>;
|
|
669
703
|
setChain(origin: string, chain: string): Promise<OriginPermission | null>;
|
|
670
704
|
/**
|
|
705
|
+
* @deprecated Rewrites every origin's grant to the active account, which shows that account to sites
|
|
706
|
+
* the user never connected it to (and links accounts across sites). Grants are per site now: the
|
|
707
|
+
* router shows an origin its granted accounts that are also active, and connecting another account
|
|
708
|
+
* adds it to that one origin ({@link grant}). Kept for compatibility; nothing in this package calls it.
|
|
709
|
+
*
|
|
671
710
|
* The active EVM account changed: every origin holding an EVM grant now sees `accounts` (MetaMask behaviour).
|
|
672
711
|
* An origin connected only on another chain (`accounts: []` — Solana/TON/Tron/BTC/NEAR providers, a WalletConnect
|
|
673
712
|
* session without eip155) is skipped: it never passed an EVM connect and must not learn the EVM address (scan F6/F8).
|
|
@@ -706,6 +745,21 @@ declare class OriginRefused extends Error {
|
|
|
706
745
|
constructor(message: string);
|
|
707
746
|
}
|
|
708
747
|
declare const APPROVALS_MAX_PENDING_PER_ORIGIN = 3;
|
|
748
|
+
/** Requests one site (registrable domain: every subdomain counts) may have waiting. */
|
|
749
|
+
declare const APPROVALS_MAX_PENDING_PER_SITE = 5;
|
|
750
|
+
/** Requests the whole queue holds (exempt origins not counted). */
|
|
751
|
+
declare const APPROVALS_MAX_PENDING_TOTAL = 20;
|
|
752
|
+
/** How fast one site may open sheets: a token bucket per site; running dry refuses for a cooldown that doubles on every repeat. */
|
|
753
|
+
interface ApprovalRateOptions {
|
|
754
|
+
/** Sheets a site may open at once. Default 10. */
|
|
755
|
+
burst?: number;
|
|
756
|
+
/** Sheets per second a site earns back. Default 1/6 (10 a minute). */
|
|
757
|
+
refillPerSecond?: number;
|
|
758
|
+
/** First cooldown after the bucket ran dry. Default 30 s. */
|
|
759
|
+
backoffMs?: number;
|
|
760
|
+
/** Longest cooldown; also how long a site must stay quiet for its strikes to reset. Default 10 min. */
|
|
761
|
+
maxBackoffMs?: number;
|
|
762
|
+
}
|
|
709
763
|
interface ApprovalRequest<P = unknown> {
|
|
710
764
|
id: string;
|
|
711
765
|
origin: string;
|
|
@@ -730,6 +784,28 @@ interface ApprovalQueueOptions {
|
|
|
730
784
|
refuse?: (origin: string) => string | null | undefined;
|
|
731
785
|
/** Requests one origin may have waiting (current + queued). Default {@link APPROVALS_MAX_PENDING_PER_ORIGIN}. */
|
|
732
786
|
maxPendingPerOrigin?: number;
|
|
787
|
+
/** Requests one site may have waiting. Default {@link APPROVALS_MAX_PENDING_PER_SITE}. */
|
|
788
|
+
maxPendingPerSite?: number;
|
|
789
|
+
/** Requests the queue holds in all. Default {@link APPROVALS_MAX_PENDING_TOTAL}. */
|
|
790
|
+
maxPendingTotal?: number;
|
|
791
|
+
/** Origin → site for the per-site limits. Default {@link defaultSiteOf siteOf} (conservative eTLD+1; pass a Public Suffix List based one if you ship it). */
|
|
792
|
+
siteOf?: (origin: string) => string;
|
|
793
|
+
/** Origins that skip every limit (the wallet's own pages: Send, swaps). They still queue behind other requests. */
|
|
794
|
+
exempt?: (origin: string) => boolean;
|
|
795
|
+
/** Sheet-opening rate per site; `false` turns it off. */
|
|
796
|
+
openRate?: ApprovalRateOptions | false;
|
|
797
|
+
/** Clock (ms), injectable for tests. */
|
|
798
|
+
now?: () => number;
|
|
799
|
+
}
|
|
800
|
+
/** Options of one {@link ApprovalQueue.request}. */
|
|
801
|
+
interface ApprovalRequestOptions {
|
|
802
|
+
/**
|
|
803
|
+
* Another sheet for a request the user has just approved (the fee changed before signing). It skips
|
|
804
|
+
* the queue and rate limits and is shown ahead of the requests already waiting — once per approval
|
|
805
|
+
* of the same origin, kind and chain; with no such approval behind it, it is an ordinary request.
|
|
806
|
+
* `refuse` still applies.
|
|
807
|
+
*/
|
|
808
|
+
followUp?: boolean;
|
|
733
809
|
}
|
|
734
810
|
/** The window side: open for one request, close when it is answered. `memoryApprovalWindow()` for tests. */
|
|
735
811
|
interface ApprovalWindow {
|
|
@@ -746,15 +822,39 @@ declare class ApprovalQueue {
|
|
|
746
822
|
private readonly _waiting;
|
|
747
823
|
private readonly _listeners;
|
|
748
824
|
private readonly _via;
|
|
825
|
+
private readonly _rate;
|
|
826
|
+
/** Per site: cooldown end and strikes (how many times the bucket ran dry recently). */
|
|
827
|
+
private readonly _cooldown;
|
|
828
|
+
/** Per origin + kind + chain: approvals that have not been followed up (see {@link ApprovalRequestOptions.followUp}). */
|
|
829
|
+
private readonly _approved;
|
|
749
830
|
constructor(window: ApprovalWindow, newId?: () => string, options?: ApprovalQueueOptions);
|
|
831
|
+
private site;
|
|
832
|
+
private get all();
|
|
833
|
+
/** The per-site rate: a reason to refuse, or null (and one token spent). */
|
|
834
|
+
private rateRefusal;
|
|
835
|
+
private static followUpKey;
|
|
836
|
+
/** The user approved `r`: it may be followed up once. */
|
|
837
|
+
private approved;
|
|
838
|
+
/** Spends one approval of the same origin, kind and chain; false when there is none. */
|
|
839
|
+
private spendApproval;
|
|
750
840
|
/** Enqueue and wait for the user's answer. Refuses (never queues) past the per-origin limits. */
|
|
751
|
-
request<T = unknown>(input: Omit<ApprovalRequest, 'id' | 'createdAt' | 'originWarnings' | 'via'
|
|
841
|
+
request<T = unknown>(input: Omit<ApprovalRequest, 'id' | 'createdAt' | 'originWarnings' | 'via'>, opts?: ApprovalRequestOptions): Promise<T>;
|
|
752
842
|
/** Attach (or clear) the transport note every later request from `origin` carries. */
|
|
753
843
|
setVia(origin: string, via: OriginVia | null): void;
|
|
754
844
|
/** The transport note later requests from `origin` carry (WalletConnect Verify's verdict for `wc:<topic>`), if any. */
|
|
755
845
|
viaFor(origin: string): OriginVia | undefined;
|
|
846
|
+
private isExempt;
|
|
756
847
|
/** Requests waiting for `origin` (current + queued). */
|
|
757
848
|
pendingFor(origin: string): number;
|
|
849
|
+
/** Requests waiting for any origin of `site` (current + queued). */
|
|
850
|
+
pendingForSite(site: string): number;
|
|
851
|
+
/** The site (registrable domain) the queue's limits put `origin` under. */
|
|
852
|
+
siteFor(origin: string): string;
|
|
853
|
+
/** Decline everything waiting for `origin` (its last page closed). Returns how many requests were declined. */
|
|
854
|
+
declineOrigin(origin: string, error?: Error): number;
|
|
855
|
+
/** "Decline all from this site": everything waiting for any origin of `site` (see {@link siteFor}). */
|
|
856
|
+
declineSite(site: string, error?: Error): number;
|
|
857
|
+
private declineWhere;
|
|
758
858
|
/** The request currently shown (the window asks for it by id on load). */
|
|
759
859
|
get current(): ApprovalRequest | null;
|
|
760
860
|
get queued(): number;
|
|
@@ -795,6 +895,14 @@ interface RelayErrorOptions {
|
|
|
795
895
|
declare function toRelayError(e: unknown, options?: RelayErrorOptions): RelayError;
|
|
796
896
|
/** Read-only methods answered from our RPC without asking the user. */
|
|
797
897
|
declare const READ_METHODS: ReadonlySet<string>;
|
|
898
|
+
/**
|
|
899
|
+
* Blocks an `eth_getLogs` from an origin without an EVM grant may span. A page that is not connected
|
|
900
|
+
* reads recent events (a token's latest transfers, a pool's last swaps), not history: 1000 blocks is
|
|
901
|
+
* ~3.3 h on Ethereum and ~30 min on 2 s chains, and stays inside every public RPC's own range cap,
|
|
902
|
+
* so one call cannot make the wallet's RPC scan millions of blocks for a page nobody connected.
|
|
903
|
+
* Connected origins are not bounded here (the node's own limits apply).
|
|
904
|
+
*/
|
|
905
|
+
declare const GETLOGS_MAX_SPAN_UNCONNECTED = 1000;
|
|
798
906
|
/** Methods that produce a signature — the review flow's business (step 4), never answered here. */
|
|
799
907
|
declare const SIGNING_METHODS: ReadonlySet<string>;
|
|
800
908
|
interface ConnectApproval {
|
|
@@ -841,9 +949,12 @@ declare class RequestRouter {
|
|
|
841
949
|
handle(origin: string, chain: RelayChain, method: string, rawParams: unknown): Promise<unknown>;
|
|
842
950
|
/** What a connected origin sees right now: its permitted accounts that the wallet can expose (none while locked). */
|
|
843
951
|
private visibleAccounts;
|
|
952
|
+
/** An unconnected origin's `eth_getLogs`: a block hash, or a range of at most {@link GETLOGS_MAX_SPAN_UNCONNECTED} blocks. */
|
|
953
|
+
private boundLogs;
|
|
844
954
|
/**
|
|
845
955
|
* Connected and unlocked → the accounts; otherwise the approval window (which
|
|
846
|
-
* unlocks first when needed) picks them
|
|
956
|
+
* unlocks first when needed) picks them, and they are ADDED to this origin's
|
|
957
|
+
* grant (other origins are untouched). Emits `connect` + `accountsChanged`.
|
|
847
958
|
*/
|
|
848
959
|
private connect;
|
|
849
960
|
disconnect(origin: string): Promise<void>;
|
|
@@ -885,7 +996,22 @@ interface SiweInfo {
|
|
|
885
996
|
problems: string[];
|
|
886
997
|
/** The header said "sign-in" but the rest did not parse as EIP-4361 (`message` then holds what could be read). */
|
|
887
998
|
malformed?: boolean;
|
|
999
|
+
/**
|
|
1000
|
+
* Set when the sign-in names another site than the one asking (its host differs from the page's
|
|
1001
|
+
* host, or from a WalletConnect Verify-attested URL): `domain` as written in the message, `origin`
|
|
1002
|
+
* the asking site as `scheme://host`. A sheet should make this its headline, not one warning among many.
|
|
1003
|
+
*/
|
|
1004
|
+
crossSite?: {
|
|
1005
|
+
domain: string;
|
|
1006
|
+
origin: string;
|
|
1007
|
+
};
|
|
888
1008
|
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Characters a sign-in message is refused for: bidi controls (ALM, LRM / RLM, embeddings, overrides,
|
|
1011
|
+
* isolates), zero-width space / joiners, word joiner and invisible operators, BOM — they can make the
|
|
1012
|
+
* domain or the statement read differently from the bytes that are signed.
|
|
1013
|
+
*/
|
|
1014
|
+
declare const SIWE_FORBIDDEN_CHARS: RegExp;
|
|
889
1015
|
interface SiweContext {
|
|
890
1016
|
/** The page that asked, as the browser recorded it (`https://…`), or a transport pseudo-origin (`wc:<topic>`). */
|
|
891
1017
|
origin: string;
|
|
@@ -903,6 +1029,15 @@ declare function parseSiwe(text: string): SiweMessage | null;
|
|
|
903
1029
|
declare function isLocalHost(host: string): boolean;
|
|
904
1030
|
/** The checks; `origin` is the page that asked (as the browser recorded it), `account` the signing address, `chainId` the site's chain. */
|
|
905
1031
|
declare function siweProblems(m: SiweMessage, ctx: SiweContext): string[];
|
|
1032
|
+
/**
|
|
1033
|
+
* The asking site when the sign-in names a different host: the browser-recorded origin, or for a
|
|
1034
|
+
* WalletConnect pseudo-origin the URL Verify attested (VALID, not scam). `null` when the hosts agree
|
|
1035
|
+
* or when no site can be vouched for at all (that case is a separate "cannot verify" problem).
|
|
1036
|
+
*/
|
|
1037
|
+
declare function siweCrossSite(m: SiweMessage, ctx: SiweContext): {
|
|
1038
|
+
domain: string;
|
|
1039
|
+
origin: string;
|
|
1040
|
+
} | null;
|
|
906
1041
|
/** `null` only when the text does not start with an EIP-4361 header; a header with unreadable fields comes back with a "malformed sign-in message" problem. */
|
|
907
1042
|
declare function describeSiwe(text: string, ctx: SiweContext): SiweInfo | null;
|
|
908
1043
|
|
|
@@ -928,7 +1063,10 @@ declare function describeSiwe(text: string, ctx: SiweContext): SiweInfo | null;
|
|
|
928
1063
|
* The fee caps signed are the ones shown, unless the network outgrew them
|
|
929
1064
|
* while the sheet was open (EIP-1559: base fee + tip above the shown cap;
|
|
930
1065
|
* legacy: a higher gas price) — then the user is asked again with the new
|
|
931
|
-
* numbers (`repriced: true`)
|
|
1066
|
+
* numbers (`repriced: true`, `repricedFrom` = the max fee shown before) on a
|
|
1067
|
+
* follow-up sheet the queue limits do not refuse, at most {@link MAX_FEE_REASKS}
|
|
1068
|
+
* times in a row; declining it signs nothing. A new max fee above the wallet's
|
|
1069
|
+
* own ceiling ({@link SignDeps.feeCeiling}) is refused without a sheet.
|
|
932
1070
|
*
|
|
933
1071
|
* The review payload ({@link SignApproval}) carries what the window shows: the
|
|
934
1072
|
* classified request, the prepared fields, the fee, and the preview the wallet
|
|
@@ -941,16 +1079,19 @@ declare function describeSiwe(text: string, ctx: SiweContext): SiweInfo | null;
|
|
|
941
1079
|
type SignRequestInfo = {
|
|
942
1080
|
kind: 'sign-message';
|
|
943
1081
|
method: 'personal_sign';
|
|
944
|
-
account: string; /** Decoded text when printable, else the hex. */
|
|
1082
|
+
account: string; /** Decoded text when printable, else the hex; invisible / direction-changing characters shown as `⟨U+XXXX⟩` ({@link revealHidden}). */
|
|
945
1083
|
text: string; /** What is actually signed (hex or utf-8 string). */
|
|
946
1084
|
raw: string; /** Parsed Sign-In with Ethereum (EIP-4361) with the checks against the asking origin, when the text is one. */
|
|
947
|
-
siwe?: SiweInfo;
|
|
1085
|
+
siwe?: SiweInfo; /** `text` had invisible or direction-changing characters (now escaped): the sheet should warn. */
|
|
1086
|
+
hiddenChars?: true; /** The message is exactly 32 bytes (`0x` + 64 hex): a blind hash signature that CoW Protocol (`ethsign`), Safe (v > 30) and others accept as an order or a transfer. Only with the wallet's opt-in ({@link SignDeps.allowBlindHash}); the sheet must make it a danger screen. */
|
|
1087
|
+
blindHash?: true;
|
|
948
1088
|
} | {
|
|
949
1089
|
kind: 'sign-typed-data';
|
|
950
1090
|
method: string;
|
|
951
|
-
account: string; /** Pretty-printed JSON. */
|
|
1091
|
+
account: string; /** Pretty-printed JSON, invisible / direction-changing characters escaped. */
|
|
952
1092
|
text: string;
|
|
953
|
-
typedData: TypedData;
|
|
1093
|
+
typedData: TypedData; /** `text` had invisible or direction-changing characters (now escaped): the sheet should warn. */
|
|
1094
|
+
hiddenChars?: true;
|
|
954
1095
|
} | {
|
|
955
1096
|
kind: 'send-transaction';
|
|
956
1097
|
method: 'eth_sendTransaction';
|
|
@@ -981,6 +1122,15 @@ interface PreparedTx {
|
|
|
981
1122
|
gasPrice?: string;
|
|
982
1123
|
/** gasLimit × max fee, base units. */
|
|
983
1124
|
maxFee: string;
|
|
1125
|
+
/**
|
|
1126
|
+
* Set when the page chose the gas limit and the wallet's own `eth_estimateGas` answered: the estimate
|
|
1127
|
+
* (0x hex) and whether the page's limit is above max(estimate × 1.5, estimate + 50 000) — then the sheet
|
|
1128
|
+
* should warn with the max fee. The page's limit is still the one signed.
|
|
1129
|
+
*/
|
|
1130
|
+
gasCheck?: {
|
|
1131
|
+
estimate: string;
|
|
1132
|
+
excessive: boolean;
|
|
1133
|
+
};
|
|
984
1134
|
}
|
|
985
1135
|
/** The approval window's payload for the three signing kinds. */
|
|
986
1136
|
interface SignApproval {
|
|
@@ -989,6 +1139,8 @@ interface SignApproval {
|
|
|
989
1139
|
prepared?: PreparedTx;
|
|
990
1140
|
/** A second sheet for the same transaction: the network's fee outgrew the cap the first one showed. */
|
|
991
1141
|
repriced?: true;
|
|
1142
|
+
/** With `repriced`: the max fee (`prepared.maxFee`, base units) the sheet before this one showed. */
|
|
1143
|
+
repricedFrom?: string;
|
|
992
1144
|
/** What the wallet attached (tx-preview-evm `TxPreview`, typed-data description…). */
|
|
993
1145
|
preview: unknown;
|
|
994
1146
|
}
|
|
@@ -1024,8 +1176,33 @@ interface SignDeps {
|
|
|
1024
1176
|
}): Promise<unknown>;
|
|
1025
1177
|
/** Tip floor per chain id in wei (default 0.1 gwei everywhere). */
|
|
1026
1178
|
tipFloor?: (chainId: number) => bigint;
|
|
1179
|
+
/**
|
|
1180
|
+
* Whether a personal_sign of a raw 32-byte hash may reach the sheet (read per request). Default: refused — a
|
|
1181
|
+
* blind hash signature can be a CoW order or a Safe transaction paying someone else (extension audit E55).
|
|
1182
|
+
*/
|
|
1183
|
+
allowBlindHash?: () => boolean | Promise<boolean>;
|
|
1184
|
+
/**
|
|
1185
|
+
* The most one transaction may cost in fee on `network` (base units), when the wallet has such a limit
|
|
1186
|
+
* (the one its signer enforces). A fee that rose above it after the sheet is refused right away, with
|
|
1187
|
+
* no second sheet. The first sheet is not checked here: the signer is the guard for it.
|
|
1188
|
+
*/
|
|
1189
|
+
feeCeiling?: (network: EvmNetwork) => bigint | undefined;
|
|
1027
1190
|
}
|
|
1028
|
-
/**
|
|
1191
|
+
/** How many times in a row one transaction's fee may be asked again ({@link SignApproval.repriced}); the next rise stops the request, nothing signed. */
|
|
1192
|
+
declare const MAX_FEE_REASKS = 3;
|
|
1193
|
+
/**
|
|
1194
|
+
* Text for a review sheet: every invisible or direction-changing character replaced by a visible
|
|
1195
|
+
* `⟨U+XXXX⟩`, so the order on screen is the order of the bytes (a right-to-left override can make
|
|
1196
|
+
* "exe.gnp" read as "png.exe"). `hidden` says whether anything was replaced — the sheet should warn.
|
|
1197
|
+
*/
|
|
1198
|
+
declare function revealHidden(text: string): {
|
|
1199
|
+
text: string;
|
|
1200
|
+
hidden: boolean;
|
|
1201
|
+
};
|
|
1202
|
+
/**
|
|
1203
|
+
* Vaulty's `messageText`: hex that decodes to printable text is shown decoded; binary payloads stay hex.
|
|
1204
|
+
* Invisible and direction-changing characters come back escaped ({@link revealHidden}).
|
|
1205
|
+
*/
|
|
1029
1206
|
declare function messageText(value: unknown): string;
|
|
1030
1207
|
/**
|
|
1031
1208
|
* The message as the signer will sign it: hex decoded when it is valid UTF-8, whatever
|
|
@@ -1033,7 +1210,6 @@ declare function messageText(value: unknown): string;
|
|
|
1033
1210
|
* signed, not the hex fallback `messageText` shows for unprintable text).
|
|
1034
1211
|
*/
|
|
1035
1212
|
declare function decodedMessage(value: unknown): string | null;
|
|
1036
|
-
/** Signing method + params → what the window reviews, or the error to answer with. */
|
|
1037
1213
|
declare function classifySignRequest(input: {
|
|
1038
1214
|
network: EvmNetwork;
|
|
1039
1215
|
method: string;
|
|
@@ -1041,9 +1217,16 @@ declare function classifySignRequest(input: {
|
|
|
1041
1217
|
accounts: string[]; /** The asking page (browser-recorded) — needed for the SIWE domain check. */
|
|
1042
1218
|
origin?: string; /** Transport note for pseudo-origins (WalletConnect Verify), for the SIWE check. */
|
|
1043
1219
|
via?: OriginVia;
|
|
1044
|
-
now?: number;
|
|
1220
|
+
now?: number; /** Let a 32-byte hash personal_sign reach the sheet (marked `blindHash`) instead of refusing it. Default false. */
|
|
1221
|
+
allowBlindHash?: boolean;
|
|
1045
1222
|
}): SignRequestInfo | RelayError;
|
|
1046
|
-
/**
|
|
1223
|
+
/** A page's gas limit above max(estimate × 1.5, estimate + 50 000) is flagged on the sheet (never replaced). */
|
|
1224
|
+
declare function gasLimitExcessive(limit: bigint, estimate: bigint): boolean;
|
|
1225
|
+
/**
|
|
1226
|
+
* Nonce, gas, fees from the wallet's RPC. A gas limit the page set is used as given, but it is checked
|
|
1227
|
+
* against the wallet's own estimate ({@link PreparedTx.gasCheck}); a failed estimate (a call that
|
|
1228
|
+
* reverts now) leaves the check out instead of failing the request.
|
|
1229
|
+
*/
|
|
1047
1230
|
declare function prepareTransaction(deps: Pick<SignDeps, 'rpc' | 'tipFloor'>, network: EvmNetwork, from: string, tx: {
|
|
1048
1231
|
to: string;
|
|
1049
1232
|
value: string;
|
|
@@ -1166,6 +1349,40 @@ interface RouteView {
|
|
|
1166
1349
|
etaSeconds: number;
|
|
1167
1350
|
validUntilMs: number;
|
|
1168
1351
|
tags: ('best' | 'fastest')[];
|
|
1352
|
+
/** Why this route is not a plain pick: a flagged route is never BEST (see {@link rank}). Absent when there is nothing to say. */
|
|
1353
|
+
warnings?: RouteWarning[];
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* What the wallet cannot vouch for on a route — data for the app's list and sheet, never a refusal:
|
|
1357
|
+
* - `min-below-slippage`: the provider's minimum sits `minGapBps` under its own quote, further than the `slippageBps`
|
|
1358
|
+
* the app asked for (a backend that inflates the output and drops the minimum would otherwise win BEST);
|
|
1359
|
+
* - `deposit-address`: the route pays an address the provider's server assigns (a 1Click deposit address, a THORChain
|
|
1360
|
+
* inbound vault on a non-EVM source chain, a Bitcoin deposit address), so where the funds end up is that server's
|
|
1361
|
+
* word, not calldata the wallet can check.
|
|
1362
|
+
*/
|
|
1363
|
+
type RouteWarning = {
|
|
1364
|
+
kind: 'min-below-slippage';
|
|
1365
|
+
slippageBps: number;
|
|
1366
|
+
minGapBps: number;
|
|
1367
|
+
} | {
|
|
1368
|
+
kind: 'deposit-address';
|
|
1369
|
+
};
|
|
1370
|
+
/** The app's route policy inputs for {@link rank}. */
|
|
1371
|
+
interface RankOptions {
|
|
1372
|
+
/** The slippage the quotes were requested at (bps): a route whose minimum sits further under its output is flagged and never BEST. */
|
|
1373
|
+
slippageBps?: number;
|
|
1374
|
+
/**
|
|
1375
|
+
* Providers whose routes pay an address their server assigns (NEAR Intents 1Click): flagged, and BEST only when no
|
|
1376
|
+
* route from any other provider exists. Which providers these are is the app's call.
|
|
1377
|
+
*/
|
|
1378
|
+
depositAddressProviders?: readonly string[];
|
|
1379
|
+
/**
|
|
1380
|
+
* The same flag per route, for a provider that pays a server-assigned address only on some routes (a THORChain
|
|
1381
|
+
* inbound vault on a non-EVM source chain, a Bitcoin deposit address) and verifiable calldata on the rest. A route is
|
|
1382
|
+
* flagged when its provider is listed above OR this returns true; a throw counts as flagged. BEST goes to a flagged
|
|
1383
|
+
* route only when every route is flagged. Which routes these are is the app's call.
|
|
1384
|
+
*/
|
|
1385
|
+
depositAddressRoute?: (quote: Quote) => boolean;
|
|
1169
1386
|
}
|
|
1170
1387
|
interface RouteListView {
|
|
1171
1388
|
routes: RouteView[];
|
|
@@ -1178,6 +1395,10 @@ interface RouteListView {
|
|
|
1178
1395
|
}
|
|
1179
1396
|
interface QuoteRoutesOptions {
|
|
1180
1397
|
onUpdate?: (view: RouteListView) => void;
|
|
1398
|
+
/** See {@link RankOptions.depositAddressProviders}; the slippage comes from `params.slippageBps`. */
|
|
1399
|
+
depositAddressProviders?: readonly string[];
|
|
1400
|
+
/** {@link RankOptions.depositAddressRoute} with the request next to the quote (a quote does not name its source chain). */
|
|
1401
|
+
depositAddressRoute?: (quote: Quote, params: QuoteParams) => boolean;
|
|
1181
1402
|
/** Per-provider wall clock (default 20 s). */
|
|
1182
1403
|
timeoutMs?: number;
|
|
1183
1404
|
signal?: AbortSignal;
|
|
@@ -1185,8 +1406,15 @@ interface QuoteRoutesOptions {
|
|
|
1185
1406
|
}
|
|
1186
1407
|
/** Dry quotes from every enabled provider that claims the route, progressively. */
|
|
1187
1408
|
declare function quoteRoutes(providers: readonly CrossChainProvider[], params: QuoteParams, options?: QuoteRoutesOptions): Promise<RouteListView>;
|
|
1188
|
-
/**
|
|
1189
|
-
|
|
1409
|
+
/**
|
|
1410
|
+
* Highest output first (same destination token for every quote); FASTEST = lowest ETA among them.
|
|
1411
|
+
*
|
|
1412
|
+
* BEST goes to the highest output among the routes without a {@link RouteWarning} that bars it: never a route whose
|
|
1413
|
+
* minimum is below the requested slippage, and a deposit-address route only when every route is one (no route with
|
|
1414
|
+
* verifiable calldata exists).
|
|
1415
|
+
* The BEST route is listed first; the rest keep the output order. With no route eligible there is no BEST.
|
|
1416
|
+
*/
|
|
1417
|
+
declare function rank(quotes: Quote[], options?: RankOptions): RouteView[];
|
|
1190
1418
|
/** Vaulty's execution floor: 50 bps under the quoted minimum rides normal drift while the user reviews, still refuses a real reprice. */
|
|
1191
1419
|
declare const FLOOR_TOLERANCE_BPS = 50n;
|
|
1192
1420
|
declare function executionFloor(minDestAmount: bigint): bigint;
|
|
@@ -1204,6 +1432,14 @@ interface SwapReviewMeta {
|
|
|
1204
1432
|
toChainName: string;
|
|
1205
1433
|
/** All of the user's addresses — recipient own/foreign. */
|
|
1206
1434
|
own: string[];
|
|
1435
|
+
/** The slippage the swap was quoted at (bps): a plan minimum further under its output is warned on the sheet (never refused). */
|
|
1436
|
+
slippageBps?: number;
|
|
1437
|
+
/**
|
|
1438
|
+
* The route pays an address the provider's server assigned (a NEAR Intents 1Click deposit address, a THORChain
|
|
1439
|
+
* inbound vault on a non-EVM source chain, a Bitcoin deposit address — the app's call per route): the sheet warns,
|
|
1440
|
+
* and the recipient check does not pass on `plan.recipient` alone — the transaction does not carry it.
|
|
1441
|
+
*/
|
|
1442
|
+
depositAddressAssignedByProvider?: boolean;
|
|
1207
1443
|
}
|
|
1208
1444
|
/** What the swap sheet renders. Amounts are base-unit strings. */
|
|
1209
1445
|
interface SwapApproval {
|
|
@@ -1262,6 +1498,14 @@ interface SwapApproval {
|
|
|
1262
1498
|
status: 'ok' | 'warn' | 'unknown';
|
|
1263
1499
|
label: string;
|
|
1264
1500
|
}[];
|
|
1501
|
+
/** With `meta.slippageBps`: how far the minimum sits under the output, and whether that is more than the slippage. */
|
|
1502
|
+
slippage?: {
|
|
1503
|
+
bps: number;
|
|
1504
|
+
minGapBps: number;
|
|
1505
|
+
below: boolean;
|
|
1506
|
+
};
|
|
1507
|
+
/** With `meta.depositAddressAssignedByProvider`: the funds go to an address the provider's server named. */
|
|
1508
|
+
depositAssignedByProvider?: true;
|
|
1265
1509
|
}
|
|
1266
1510
|
declare const encodeApproveCalldata: (spender: string, amount: bigint) => string;
|
|
1267
1511
|
declare function swapApprovalPayload(plan: Swap2ExecutionPlan, meta: SwapReviewMeta): SwapApproval;
|
|
@@ -1438,56 +1682,20 @@ declare function earnApprovalPayload(plan: EarnPlan, meta: EarnReviewMeta): Earn
|
|
|
1438
1682
|
/** One sheet for the plan; approve → pre-approve exactly its calls; decline → ReviewDeclined, nothing sent. */
|
|
1439
1683
|
declare function reviewEarnPlan(approvals: ApprovalQueue, gate: ReviewGate, meta: EarnReviewMeta, plan: EarnPlan): Promise<void>;
|
|
1440
1684
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
manifestUrl: string;
|
|
1456
|
-
/** `ton_addr` always; `ton_proof` with the dApp's payload when asked. */
|
|
1457
|
-
proofPayload?: string;
|
|
1458
|
-
}
|
|
1459
|
-
declare function parseConnectRequest(message: unknown): TonConnectRequest;
|
|
1460
|
-
interface TonConnectMessage {
|
|
1461
|
-
/** Destination, as given (friendly or raw). */
|
|
1462
|
-
address: string;
|
|
1463
|
-
/** Nanotons, decimal string. */
|
|
1464
|
-
amount: string;
|
|
1465
|
-
/** base64 BoC body. */
|
|
1466
|
-
payload?: string;
|
|
1467
|
-
/** base64 BoC state init. */
|
|
1468
|
-
stateInit?: string;
|
|
1469
|
-
}
|
|
1470
|
-
interface TonConnectSendTransaction {
|
|
1471
|
-
validUntil?: number;
|
|
1472
|
-
network?: string;
|
|
1473
|
-
from?: string;
|
|
1474
|
-
messages: TonConnectMessage[];
|
|
1475
|
-
}
|
|
1476
|
-
declare const TONCONNECT_MAX_MESSAGES = 4;
|
|
1477
|
-
/** `sendTransaction` params[0] (a JSON string per the spec, or an object). */
|
|
1478
|
-
declare function parseSendTransaction(param: unknown, options?: {
|
|
1479
|
-
maxMessages?: number;
|
|
1480
|
-
network?: string;
|
|
1481
|
-
}): TonConnectSendTransaction;
|
|
1482
|
-
type TonSignDataPayload = {
|
|
1483
|
-
type: 'text';
|
|
1484
|
-
text: string;
|
|
1485
|
-
} | {
|
|
1486
|
-
type: 'binary';
|
|
1487
|
-
bytes: string;
|
|
1488
|
-
};
|
|
1489
|
-
/** `signData` params[0]: text or binary only — `cell` payloads need schema-aware rendering and are refused by name. */
|
|
1490
|
-
declare function parseSignData(param: unknown): TonSignDataPayload;
|
|
1685
|
+
/**
|
|
1686
|
+
* TON Connect protocol v2 for the extension's JS bridge. Request parsing, error codes and the
|
|
1687
|
+
* signature digests live in one place, `@anywalletkit/wallet-ton/tonconnect`, shared with the
|
|
1688
|
+
* WalletConnect transport (`@anywalletkit/walletconnect-ton`); this module re-exports them and
|
|
1689
|
+
* keeps the bridge-side helpers (the page origin as the proof domain, relay errors as TON Connect
|
|
1690
|
+
* codes). The wallet side (keys, sheet, broadcast) lives in the extension; nothing here touches a key.
|
|
1691
|
+
*
|
|
1692
|
+
* To SIGN, use `WalletAccountTon.signTonProof` / `signTonConnectData` (wallet-ton): they build the
|
|
1693
|
+
* same digests from the request and the account's own address. `account.sign()` refuses these
|
|
1694
|
+
* 32-byte digests — 32 raw bytes may as well be the hash of a transfer — so the digest functions
|
|
1695
|
+
* here are for checking a proof, not for feeding `sign()`.
|
|
1696
|
+
*/
|
|
1697
|
+
|
|
1698
|
+
/** Workchain and 32-byte account hash of a TON address. */
|
|
1491
1699
|
interface TonAddressParts {
|
|
1492
1700
|
workchain: number;
|
|
1493
1701
|
hash: Uint8Array;
|
|
@@ -1506,7 +1714,7 @@ declare function tonSignDataMessage(input: {
|
|
|
1506
1714
|
timestamp: number;
|
|
1507
1715
|
payload: TonSignDataPayload;
|
|
1508
1716
|
}): Uint8Array;
|
|
1509
|
-
/** `0:abcd…` → parts
|
|
1717
|
+
/** `0:abcd…` → parts. Friendly addresses are the wallet package's job (it hands us the raw form). */
|
|
1510
1718
|
declare function parseRawAddress(raw: string): TonAddressParts;
|
|
1511
1719
|
/** The dApp's domain for proofs, from the page origin (host only, as the spec's `domain.value`). */
|
|
1512
1720
|
declare function proofDomain(origin: string): string;
|
|
@@ -1640,6 +1848,8 @@ declare class RecipientBook {
|
|
|
1640
1848
|
private state;
|
|
1641
1849
|
list(namespace: string): Promise<string[]>;
|
|
1642
1850
|
remember(namespace: string, address: string): Promise<void>;
|
|
1851
|
+
/** Forget the cached book: the next read asks storage again (e.g. a storage that only answers once the wallet is unlocked). */
|
|
1852
|
+
reload(): void;
|
|
1643
1853
|
/** `known` → the address is one the user paid before; `lookalike` → it imitates one. */
|
|
1644
1854
|
check(namespace: string, address: string): Promise<{
|
|
1645
1855
|
known: boolean;
|
|
@@ -1647,4 +1857,209 @@ declare class RecipientBook {
|
|
|
1647
1857
|
}>;
|
|
1648
1858
|
}
|
|
1649
1859
|
|
|
1650
|
-
|
|
1860
|
+
/** Field of the stored envelope that holds the MAC (base64), or `null` for a value written without a key. */
|
|
1861
|
+
declare const STORAGE_MAC_FIELD = "anywalletkit.mac/1";
|
|
1862
|
+
/** Field of the stored envelope that holds the value's version (a positive integer, inside the MAC) when the store has a {@link storageVersionLedger}. */
|
|
1863
|
+
declare const STORAGE_VERSION_FIELD = "anywalletkit.ver/1";
|
|
1864
|
+
/**
|
|
1865
|
+
* The storage MAC key: HKDF-SHA256(ikm = DEK, salt = none, info = "anywalletkit/storage-mac/1"), 32
|
|
1866
|
+
* bytes. One-way — it reveals nothing about the DEK — so a wallet may keep it in
|
|
1867
|
+
* `chrome.storage.session` while locked. The same DEK always gives the same key; a rotated DEK a new one.
|
|
1868
|
+
*/
|
|
1869
|
+
declare function deriveStorageMacKey(dek: Uint8Array, crypto?: Crypto): Promise<Uint8Array>;
|
|
1870
|
+
/**
|
|
1871
|
+
* What a read found:
|
|
1872
|
+
* - `ok`: a value with a valid MAC;
|
|
1873
|
+
* - `empty`: nothing stored;
|
|
1874
|
+
* - `unsigned`: a value without a MAC (written before the wrapper existed, or while no key was there);
|
|
1875
|
+
* - `invalid`: a MAC that does not match (edited, from another store, or under another key);
|
|
1876
|
+
* - `no-key`: something is stored but there is no key to check it with;
|
|
1877
|
+
* - `stale` (only with a {@link storageVersionLedger}): the MAC is valid — or nothing is stored — but
|
|
1878
|
+
* this is not the latest value the ledger knows: an older signed value put back, a deleted one, or
|
|
1879
|
+
* a ledger that was itself removed, edited or rolled back.
|
|
1880
|
+
*/
|
|
1881
|
+
type MacState = 'ok' | 'empty' | 'unsigned' | 'invalid' | 'no-key' | 'stale';
|
|
1882
|
+
interface MacRead<T> {
|
|
1883
|
+
state: MacState;
|
|
1884
|
+
/** The stored value — verified only when `state` is `ok`. */
|
|
1885
|
+
value: T | null;
|
|
1886
|
+
/** With a ledger, for a value whose MAC is valid: its version (`0` = signed before versions existed). */
|
|
1887
|
+
version?: number;
|
|
1888
|
+
}
|
|
1889
|
+
interface MacJsonStorageOptions {
|
|
1890
|
+
/** Names the store inside the MAC: a value signed for one store does not verify in another. */
|
|
1891
|
+
label: string;
|
|
1892
|
+
/** The MAC key ({@link deriveStorageMacKey}), or `null` when the wallet has none (locked). The wrapper zeroizes the copy it gets. */
|
|
1893
|
+
key: () => Promise<Uint8Array | null>;
|
|
1894
|
+
/** `get()` without a key: the stored value unverified (`'unverified'`, default) or `null`. */
|
|
1895
|
+
readWithoutKey?: 'unverified' | 'null';
|
|
1896
|
+
/** `set()` without a key: store the value with no MAC (`'unsigned'`, default — it fails verification later) or throw `VaultError('locked')`. */
|
|
1897
|
+
writeWithoutKey?: 'unsigned' | 'refuse';
|
|
1898
|
+
/**
|
|
1899
|
+
* Rollback protection: the ledger shared by the wallet's signed stores. Every signed write takes the
|
|
1900
|
+
* store's next version (inside the MAC) and records it; a read whose version the ledger does not
|
|
1901
|
+
* agree with is `stale`. The label must not contain a line break.
|
|
1902
|
+
*/
|
|
1903
|
+
versions?: StorageVersionLedger;
|
|
1904
|
+
}
|
|
1905
|
+
interface MacJsonStorage<T> extends JsonStorage<T> {
|
|
1906
|
+
/** The verified value (`null` when empty, unsigned or invalid); without a key, per `readWithoutKey`. */
|
|
1907
|
+
get(): Promise<T | null>;
|
|
1908
|
+
/** Sign with the current key; without one, per `writeWithoutKey`. */
|
|
1909
|
+
set(value: T): Promise<void>;
|
|
1910
|
+
/** The stored value and what verification found, under `key` (default: the current key). */
|
|
1911
|
+
read(key?: Uint8Array): Promise<MacRead<T>>;
|
|
1912
|
+
/** Store `value` signed under `key` (default: the current key; refused without one). */
|
|
1913
|
+
write(value: T, key?: Uint8Array): Promise<void>;
|
|
1914
|
+
/**
|
|
1915
|
+
* Re-sign the stored value under `newKey` when it verifies under `oldKey`; anything else is left as it is. Returns what `oldKey` found.
|
|
1916
|
+
* With a ledger: rekey the ledger first ({@link StorageVersionLedger.rekey}); the value keeps its version, and is re-signed only when the
|
|
1917
|
+
* re-signed ledger agrees with it (`stale` otherwise).
|
|
1918
|
+
*/
|
|
1919
|
+
rekey(oldKey: Uint8Array, newKey: Uint8Array): Promise<MacState>;
|
|
1920
|
+
}
|
|
1921
|
+
/** Wrap `inner` (e.g. `chromeJsonStorage(chrome.storage.local, key)`) with a MAC; see the module comment. */
|
|
1922
|
+
declare function macJsonStorage<T>(inner: JsonStorage<unknown>, options: MacJsonStorageOptions): MacJsonStorage<T>;
|
|
1923
|
+
/** Deterministic JSON: the same data gives the same text whatever order its keys were stored in. */
|
|
1924
|
+
declare function canonicalJson(value: unknown): string;
|
|
1925
|
+
/** What a {@link StorageVersionLedger} holds, as {@link StorageVersionLedger.read} found it. */
|
|
1926
|
+
interface StorageVersions {
|
|
1927
|
+
/** `ok`; `empty` (no manifest and none expected); `invalid` (unsigned, edited, or another key); `stale` (missing or older than this browser session has seen). */
|
|
1928
|
+
state: 'ok' | 'empty' | 'invalid' | 'stale';
|
|
1929
|
+
/** Goes up by one with every manifest write. `0` when there is no readable manifest. */
|
|
1930
|
+
epoch: number;
|
|
1931
|
+
/** Where this manifest's numbering started: a store's first version is `base + 1`. */
|
|
1932
|
+
base: number;
|
|
1933
|
+
/** After {@link StorageVersionLedger.condemn}: a store the manifest does not list is not trusted, stored or not. */
|
|
1934
|
+
sealed: boolean;
|
|
1935
|
+
/** The latest version of each store, by label. */
|
|
1936
|
+
versions: Record<string, number>;
|
|
1937
|
+
}
|
|
1938
|
+
/** The ledger operations a store runs inside {@link StorageVersionLedger.exclusive}. */
|
|
1939
|
+
interface StorageVersionOps {
|
|
1940
|
+
/**
|
|
1941
|
+
* Is `version` the latest for `label`? `null` = nothing is stored, `0` = a signed value without a
|
|
1942
|
+
* version. A value exactly one ahead of the manifest is accepted and recorded (an interrupted write).
|
|
1943
|
+
*/
|
|
1944
|
+
check(label: string, version: number | null, key: Uint8Array): Promise<'ok' | 'stale'>;
|
|
1945
|
+
/**
|
|
1946
|
+
* One write: `write(version)` stores the value signed with the next version, then the manifest records
|
|
1947
|
+
* it. `seen()` is the version of the value stored now (0 when none this key signed). A missing manifest
|
|
1948
|
+
* is created first; a refused one is replaced by a sealed one ({@link StorageVersionLedger.condemn}).
|
|
1949
|
+
*/
|
|
1950
|
+
advance(label: string, key: Uint8Array, seen: () => Promise<number>, write: (version: number) => Promise<void>): Promise<number>;
|
|
1951
|
+
}
|
|
1952
|
+
interface StorageVersionLedgerOptions {
|
|
1953
|
+
/** Where the manifest lives — the same area as the stores it covers (`chrome.storage.local`). */
|
|
1954
|
+
manifest: JsonStorage<unknown>;
|
|
1955
|
+
/**
|
|
1956
|
+
* The highest manifest epoch seen, kept where a write to the stores' area cannot reach it and where it
|
|
1957
|
+
* dies with the browser session (`chrome.storage.session`). `set(null)` clears it.
|
|
1958
|
+
*/
|
|
1959
|
+
mark: JsonStorage<unknown>;
|
|
1960
|
+
/** Names the manifest inside its MAC. No store may use it. */
|
|
1961
|
+
label?: string;
|
|
1962
|
+
/**
|
|
1963
|
+
* Accept a validly signed value that carries no version (written before the ledger existed) for a
|
|
1964
|
+
* store the manifest has no record of. Off by default: such a value can be replayed for as long as it
|
|
1965
|
+
* is accepted, so switch it on only to migrate, write every store once, and switch it off again.
|
|
1966
|
+
*/
|
|
1967
|
+
acceptUnversioned?: boolean;
|
|
1968
|
+
/** Milliseconds since the epoch — where a new manifest starts numbering. */
|
|
1969
|
+
now?: () => number;
|
|
1970
|
+
}
|
|
1971
|
+
interface StorageVersionLedger {
|
|
1972
|
+
/** Run `fn` with no other ledger operation in between (stores use it for read-and-check and for a write). Do not nest. */
|
|
1973
|
+
exclusive<R>(fn: (ops: StorageVersionOps) => Promise<R>): Promise<R>;
|
|
1974
|
+
/**
|
|
1975
|
+
* Stop trusting everything signed so far: a fresh, sealed manifest numbered above all it replaces.
|
|
1976
|
+
* Every store then reads `stale` — also one with nothing stored — until it is written again.
|
|
1977
|
+
*/
|
|
1978
|
+
condemn(key: Uint8Array): Promise<void>;
|
|
1979
|
+
/** Re-sign the manifest under `newKey` when it is `ok` under `oldKey` (one epoch up); otherwise it is left as it is. Returns what `oldKey` found. Then rekey the stores. */
|
|
1980
|
+
rekey(oldKey: Uint8Array, newKey: Uint8Array): Promise<StorageVersions['state']>;
|
|
1981
|
+
/** The manifest as `key` sees it. */
|
|
1982
|
+
read(key: Uint8Array): Promise<StorageVersions>;
|
|
1983
|
+
/** Forget manifest and mark — only when the stores are wiped with them (a new vault). */
|
|
1984
|
+
reset(): Promise<void>;
|
|
1985
|
+
}
|
|
1986
|
+
/**
|
|
1987
|
+
* Rollback protection for {@link macJsonStorage} stores: one signed manifest that says which version
|
|
1988
|
+
* of each store is the latest.
|
|
1989
|
+
*
|
|
1990
|
+
* - Every signed value carries its version inside the MAC. A write stores the value with the store's
|
|
1991
|
+
* next version, then the manifest (its `epoch` goes up by one), then the session mark. A value the
|
|
1992
|
+
* manifest lists another version for — or lists, when nothing is stored — is `stale`: putting ONE
|
|
1993
|
+
* store back, or deleting it, is caught, across browser restarts too.
|
|
1994
|
+
* - The manifest lives next to the stores, so the whole area can be put back together. `mark` — the
|
|
1995
|
+
* highest epoch seen, in session storage — catches that for as long as the browser session lives: a
|
|
1996
|
+
* manifest older than the mark, or missing while there is a mark, makes every store `stale`.
|
|
1997
|
+
* - A manifest that is unsigned, edited or under another key makes every store `stale`. So does a
|
|
1998
|
+
* signed value with a version when there is no manifest at all.
|
|
1999
|
+
* - A worker killed between the value and the manifest write leaves a value exactly one version ahead.
|
|
2000
|
+
* That is accepted and recorded: only the key holder can sign that version, so it is the wallet's own
|
|
2001
|
+
* last write. Until it is recorded the previous value still verifies — the same as the interrupted
|
|
2002
|
+
* write never having happened.
|
|
2003
|
+
*
|
|
2004
|
+
* What it cannot see: the whole area (manifest and stores together) put back to an earlier state when
|
|
2005
|
+
* there is no mark — after a browser restart, or an extension reload — and likewise everything deleted
|
|
2006
|
+
* together. Nothing an extension can store survives that and is out of the same writer's reach; it is
|
|
2007
|
+
* what restoring a profile backup looks like. Versions start from the clock (`now`) so that a manifest
|
|
2008
|
+
* created after a loss does not hand out numbers already used; a clock set far back defeats that.
|
|
2009
|
+
*
|
|
2010
|
+
* The ledger never repairs on a read (beyond recording an interrupted write): the wallet decides what
|
|
2011
|
+
* a `stale` store falls back to, calls {@link StorageVersionLedger.condemn} when the manifest itself was
|
|
2012
|
+
* refused, and writes the stores again.
|
|
2013
|
+
*/
|
|
2014
|
+
declare function storageVersionLedger(options: StorageVersionLedgerOptions): StorageVersionLedger;
|
|
2015
|
+
|
|
2016
|
+
/**
|
|
2017
|
+
* "Same site" for limits: the registrable domain (eTLD+1) of an origin, and a
|
|
2018
|
+
* token bucket keyed by any string. Both exist so a page cannot multiply its
|
|
2019
|
+
* allowance by spreading requests over subdomains (`a1.evil.tld`, `a2.evil.tld`…).
|
|
2020
|
+
*
|
|
2021
|
+
* There is no Public Suffix List in this package (it is large and changes); the
|
|
2022
|
+
* helper is conservative instead: the last two labels, or three when the last two
|
|
2023
|
+
* are a known multi-label public suffix ({@link MULTI_LABEL_SUFFIXES}: country
|
|
2024
|
+
* second-level domains such as `co.uk`, and hosting domains where anyone gets a
|
|
2025
|
+
* subdomain, such as `github.io` or `vercel.app`). A suffix that is missing from
|
|
2026
|
+
* the list makes unrelated sites under it share one limit (stricter, never looser);
|
|
2027
|
+
* pass your own `siteOf` to the queue when you ship a full list.
|
|
2028
|
+
*/
|
|
2029
|
+
/**
|
|
2030
|
+
* Multi-label public suffixes the helper knows. Two groups: country second-level
|
|
2031
|
+
* registries, and hosting platforms that hand out subdomains to anyone (the
|
|
2032
|
+
* Public Suffix List's private section).
|
|
2033
|
+
*/
|
|
2034
|
+
declare const MULTI_LABEL_SUFFIXES: ReadonlySet<string>;
|
|
2035
|
+
/**
|
|
2036
|
+
* The site an origin belongs to: `https://a.b.example.co.uk:8443` → `example.co.uk`,
|
|
2037
|
+
* `https://x.vercel.app` → `x.vercel.app`. IP addresses and single-label hosts
|
|
2038
|
+
* (`localhost`) are their own site. A pseudo-origin that is not a URL (`wc:<topic>`)
|
|
2039
|
+
* is returned unchanged.
|
|
2040
|
+
*/
|
|
2041
|
+
declare function siteOf(origin: string): string;
|
|
2042
|
+
interface TokenBucketOptions {
|
|
2043
|
+
/** Tokens a key holds when full (the burst). */
|
|
2044
|
+
capacity: number;
|
|
2045
|
+
/** Tokens added per second. */
|
|
2046
|
+
refillPerSecond: number;
|
|
2047
|
+
/** Clock (ms), injectable for tests. */
|
|
2048
|
+
now?: () => number;
|
|
2049
|
+
/** Keys tracked before full buckets are dropped (memory bound). Default 2000. */
|
|
2050
|
+
maxKeys?: number;
|
|
2051
|
+
}
|
|
2052
|
+
/** A token bucket per key: `take(key)` spends one token, `false` when the key is out of tokens. Memory only. */
|
|
2053
|
+
declare class TokenBucket {
|
|
2054
|
+
private readonly options;
|
|
2055
|
+
private readonly buckets;
|
|
2056
|
+
constructor(options: TokenBucketOptions);
|
|
2057
|
+
take(key: string, cost?: number): boolean;
|
|
2058
|
+
/** Tokens `key` holds right now (full for an unknown key). */
|
|
2059
|
+
available(key: string): number;
|
|
2060
|
+
private refill;
|
|
2061
|
+
/** Drop buckets that are full again (they carry no state); the oldest half when every one is in use. */
|
|
2062
|
+
private prune;
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
export { ACTIVE_STATUSES, APPROVALS_MAX_PENDING_PER_ORIGIN, APPROVALS_MAX_PENDING_PER_SITE, APPROVALS_MAX_PENDING_TOTAL, type AddChainApproval, type AlarmsLike, type ApprovalKind, ApprovalQueue, type ApprovalQueueOptions, type ApprovalRateOptions, type ApprovalRequest, type ApprovalRequestOptions, type ApprovalWindow, type AssertionExpectations, type AssertionInput, type AssertionVerdict, BTC_CHAIN, BTC_ESPLORA, CHAIN_ACCOUNT_KEYS, type ChainAccountsKey, type ChainDescriptor, type ConnectApproval, DEFAULT_CHAIN, DEFAULT_NETWORKS, type EarnApproval, type EarnPlan, type EarnReviewMeta, type EarnTx, type EvmNetwork, type EvmSigner, FLOOR_TOLERANCE_BPS, GETLOGS_MAX_SPAN_UNCONNECTED, type GateMatcher, type GatedOp, type HostCheck, type JsonStorage, KEYRING_STORAGE_KEY, LOOKALIKE_PREFIX, LOOKALIKE_SUFFIX, MAX_FEE_REASKS, MULTI_LABEL_SUFFIXES, type MacJsonStorage, type MacJsonStorageOptions, type MacRead, type MacState, NEAR_CHAIN, NEAR_PROVIDERS, NON_EVM_CHAINS, NetworksTable, type OriginPermission, OriginRefused, type OriginVia, PAGE_TARGET, PORT_NAME, type PageEvent, type PageMessageEvent, type PageRequest, type PageResponse, type PageWindow, PermissionStore, type PermissionsState, PhishingDetector, type PhishingList, type PortSender, type PreparedTx, QueueLimitError, type QuoteRoutesOptions, READ_METHODS, RELAY_ERRORS, RELAY_METHOD_MAX, type RankOptions, RecipientBook, type RecipientsState, type RelayChain, type RelayError, type RelayErrorOptions, type RelayEvent, type RelayRequest, type RelayResponse, type RelayToContent, type RelayToWorker, RequestRouter, ReviewDeclined, ReviewGate, type RouteListView, type RouteView, type RouteWarning, type RouterDeps, RouterError, SESSION_DEFAULT_AUTOLOCK_MS, SIGNING_METHODS, SIWE_FORBIDDEN_CHARS, SOLANA_CHAIN, SOLANA_RPCS, STORAGE_MAC_FIELD, STORAGE_VERSION_FIELD, type SealedBox, Session, type SessionAlarms, type SessionOptions, type SessionStorage, type SignApproval, type SignDeps, type SignRequestInfo, type SiweContext, type SiweInfo, type SiweMessage, type StorageAreaLike, type StorageVersionLedger, type StorageVersionLedgerOptions, type StorageVersionOps, type StorageVersions, type SwapApproval, type SwapRecord, type SwapRecordStatus, type SwapReviewMeta, SwapTracker, type SwapTrackerDeps, SwapsStore, type SwitchChainApproval, TON_CHAIN, TON_ENDPOINTS, TRON_CHAIN, TRON_PROVIDERS, TokenBucket, type TokenBucketOptions, type TonAddressParts, type TypedData, VAULT_DEFAULT_ITERATIONS, VAULT_LIMITS, VAULT_MIN_ITERATIONS, VAULT_MIN_PASSWORD_LENGTH, VAULT_MIN_SCRYPT, VAULT_SCRYPT, VAULT_STORAGE_KEY, Vault, type VaultEnvelope, type VaultEnvelopeV1, type VaultEnvelopeV2, VaultError, type VaultErrorCode, type VaultKdfInfo, type VaultOptions, type VaultPasskey, type VaultStorage, ZCASH_BLOCKCHAIR, ZCASH_CHAIN, approvalChallenge, caip2FromChainId, canonicalJson, chainHex, chainTxMatcher, checkSenderOrigin, chromeAlarms, chromeJsonStorage, chromeKeyringStorage, chromeLocalVaultStorage, chromeSessionStorage, classifySignRequest, createSignHandler, decodedMessage, derToRaw, deriveStorageMacKey, describeSiwe, earnApprovalPayload, earnPlanMatchers, encodeApproveCalldata, evmCallMatcher, executionFloor, fromBase64Url, gasLimitExcessive, hostOf, isCatalogChain, isEnvelopeV1, isEnvelopeV2, isLocalHost, isPageEvent, isPageRequest, isPageResponse, isRelayMethod, isRelayRequest, isRelayToContent, levenshtein, lookalikeOf, macJsonStorage, memoryAlarms, memoryApprovalWindow, memoryJsonStorage, memorySessionStorage, memoryVaultStorage, messageText, newRequestId, nonEvmChain, normalizeHost, pageRequestFrom, parseAddChainParams, parseRawAddress, parseSiwe, parseSwapId, planMatchers, prepareTransaction, proofDomain, quoteRoutes, rank, rawToDer, relayError, revealHidden, reviewEarnPlan, reviewSwapPlan, siteOf, siweCrossSite, siweProblems, stampOrigin, storageVersionLedger, swapApprovalPayload, toBase64Url, toRelayError, tonConnectErrorCode, tonProofMessage, tonSignDataMessage, typedDataMatcher, vaultSecretStorage, verifyAssertion };
|