@vultisig/core-chain 2.18.0 → 2.20.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/chains/solana/staking/config.d.ts +75 -0
  3. package/dist/chains/solana/staking/config.d.ts.map +1 -0
  4. package/dist/chains/solana/staking/config.js +75 -0
  5. package/dist/chains/solana/staking/config.js.map +1 -0
  6. package/dist/chains/solana/staking/cooldownGate.d.ts +34 -0
  7. package/dist/chains/solana/staking/cooldownGate.d.ts.map +1 -0
  8. package/dist/chains/solana/staking/cooldownGate.js +32 -0
  9. package/dist/chains/solana/staking/cooldownGate.js.map +1 -0
  10. package/dist/chains/solana/staking/models/stakeAccount.d.ts +102 -0
  11. package/dist/chains/solana/staking/models/stakeAccount.d.ts.map +1 -0
  12. package/dist/chains/solana/staking/models/stakeAccount.js +85 -0
  13. package/dist/chains/solana/staking/models/stakeAccount.js.map +1 -0
  14. package/dist/chains/solana/staking/models/validator.d.ts +62 -0
  15. package/dist/chains/solana/staking/models/validator.d.ts.map +1 -0
  16. package/dist/chains/solana/staking/models/validator.js +34 -0
  17. package/dist/chains/solana/staking/models/validator.js.map +1 -0
  18. package/dist/chains/solana/staking/rpc.d.ts +49 -0
  19. package/dist/chains/solana/staking/rpc.d.ts.map +1 -0
  20. package/dist/chains/solana/staking/rpc.js +112 -0
  21. package/dist/chains/solana/staking/rpc.js.map +1 -0
  22. package/dist/chains/ton/address.d.ts +9 -0
  23. package/dist/chains/ton/address.d.ts.map +1 -1
  24. package/dist/chains/ton/address.js +13 -0
  25. package/dist/chains/ton/address.js.map +1 -1
  26. package/dist/chains/ton/staking.d.ts +104 -0
  27. package/dist/chains/ton/staking.d.ts.map +1 -0
  28. package/dist/chains/ton/staking.js +137 -0
  29. package/dist/chains/ton/staking.js.map +1 -0
  30. package/dist/coin/balance/getEvmChainBalances.d.ts +11 -0
  31. package/dist/coin/balance/getEvmChainBalances.d.ts.map +1 -0
  32. package/dist/coin/balance/getEvmChainBalances.js +57 -0
  33. package/dist/coin/balance/getEvmChainBalances.js.map +1 -0
  34. package/dist/swap/general/GeneralSwapProvider.d.ts +1 -1
  35. package/dist/swap/general/GeneralSwapProvider.d.ts.map +1 -1
  36. package/dist/swap/general/GeneralSwapProvider.js +2 -1
  37. package/dist/swap/general/GeneralSwapProvider.js.map +1 -1
  38. package/dist/swap/general/jupiter/JupiterSwapEnabledChains.d.ts +9 -0
  39. package/dist/swap/general/jupiter/JupiterSwapEnabledChains.d.ts.map +1 -0
  40. package/dist/swap/general/jupiter/JupiterSwapEnabledChains.js +9 -0
  41. package/dist/swap/general/jupiter/JupiterSwapEnabledChains.js.map +1 -0
  42. package/dist/swap/general/jupiter/api/getJupiterSwapQuote.d.ts +25 -0
  43. package/dist/swap/general/jupiter/api/getJupiterSwapQuote.d.ts.map +1 -0
  44. package/dist/swap/general/jupiter/api/getJupiterSwapQuote.js +112 -0
  45. package/dist/swap/general/jupiter/api/getJupiterSwapQuote.js.map +1 -0
  46. package/dist/swap/general/jupiter/api/jupiterFeeAta.d.ts +48 -0
  47. package/dist/swap/general/jupiter/api/jupiterFeeAta.d.ts.map +1 -0
  48. package/dist/swap/general/jupiter/api/jupiterFeeAta.js +115 -0
  49. package/dist/swap/general/jupiter/api/jupiterFeeAta.js.map +1 -0
  50. package/dist/swap/general/jupiter/config.d.ts +13 -0
  51. package/dist/swap/general/jupiter/config.d.ts.map +1 -0
  52. package/dist/swap/general/jupiter/config.js +52 -0
  53. package/dist/swap/general/jupiter/config.js.map +1 -0
  54. package/dist/swap/quote/findSwapQuote.d.ts +1 -1
  55. package/dist/swap/quote/findSwapQuote.d.ts.map +1 -1
  56. package/dist/swap/quote/findSwapQuote.js +33 -1
  57. package/dist/swap/quote/findSwapQuote.js.map +1 -1
  58. package/dist/swap/utils/getSwapExplorerUrl/index.d.ts +2 -2
  59. package/dist/swap/utils/getSwapExplorerUrl/index.d.ts.map +1 -1
  60. package/dist/swap/utils/getSwapExplorerUrl/index.js +11 -2
  61. package/dist/swap/utils/getSwapExplorerUrl/index.js.map +1 -1
  62. package/package.json +56 -1
@@ -0,0 +1,112 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { getSolanaClient } from '../client.js';
3
+ import { solanaStakingConfig } from './config.js';
4
+ import { parseStakeAccount } from './models/stakeAccount.js';
5
+ /**
6
+ * Read-side Solana RPC for native staking. Thin wrappers over the shared
7
+ * `@solana/web3.js` connection (`getSolanaClient`) so the staking read layer
8
+ * stays one call away from the rest of the Solana chain code.
9
+ *
10
+ * Port of the Solana staking reads in iOS `SolanaService` / `SolanaAPI`.
11
+ */
12
+ /**
13
+ * Lists every validator from `getVoteAccounts`, tagging each with the
14
+ * delinquent flag derived from its bucket (`current` vs `delinquent`). The base
15
+ * metadata is left empty — the metadata-provider seam enriches it later.
16
+ */
17
+ export const fetchSolanaValidators = async () => {
18
+ const client = getSolanaClient();
19
+ const { current, delinquent } = await client.getVoteAccounts();
20
+ const toValidator = (account, isDelinquent) => ({
21
+ votePubkey: account.votePubkey,
22
+ nodePubkey: account.nodePubkey,
23
+ // `activatedStake` arrives from the RPC as a JSON number — keep it as-is
24
+ // rather than minting a falsely-exact bigint from an already-lossy value.
25
+ activatedStake: account.activatedStake,
26
+ commission: account.commission,
27
+ epochVoteAccount: account.epochVoteAccount,
28
+ isDelinquent,
29
+ metadata: {},
30
+ });
31
+ return [...current.map(a => toValidator(a, false)), ...delinquent.map(a => toValidator(a, true))];
32
+ };
33
+ /**
34
+ * Fetches the owner's stake accounts via a Stake-program `getProgramAccounts`
35
+ * scan filtered on `dataSize: 200` (fully-initialized stake accounts) and a
36
+ * memcmp on the staker authority at offset 12. Uncached at the call site — the
37
+ * staking view must reflect just-submitted txs and newly accrued rewards.
38
+ */
39
+ export const fetchSolanaStakeAccounts = async (owner) => {
40
+ const client = getSolanaClient();
41
+ const rows = await client.getParsedProgramAccounts(new PublicKey(solanaStakingConfig.stakeProgramId), {
42
+ filters: [
43
+ { dataSize: solanaStakingConfig.stakeStateSize },
44
+ { memcmp: { offset: solanaStakingConfig.stakerMemcmpOffset, bytes: owner } },
45
+ ],
46
+ });
47
+ return rows.flatMap(({ pubkey, account }) => {
48
+ const { data } = account;
49
+ if (!('parsed' in data)) {
50
+ return [];
51
+ }
52
+ const parsed = parseStakeAccount({
53
+ pubkey: pubkey.toBase58(),
54
+ lamports: BigInt(account.lamports),
55
+ parsedInfo: data.parsed?.info,
56
+ });
57
+ return parsed ? [parsed] : [];
58
+ });
59
+ };
60
+ /**
61
+ * Fetches a single stake account's parsed state by address. Used by the
62
+ * unstake / withdraw / move flows that operate on a known account.
63
+ */
64
+ export const fetchSolanaStakeAccount = async (pubkey) => {
65
+ const client = getSolanaClient();
66
+ const { value } = await client.getParsedAccountInfo(new PublicKey(pubkey));
67
+ if (!value || !('parsed' in value.data)) {
68
+ return undefined;
69
+ }
70
+ return parseStakeAccount({
71
+ pubkey,
72
+ lamports: BigInt(value.lamports),
73
+ parsedInfo: value.data.parsed?.info,
74
+ });
75
+ };
76
+ /** Current epoch info — drives activation-state derivation and cooldown copy. */
77
+ export const fetchSolanaEpochInfo = async () => {
78
+ const client = getSolanaClient();
79
+ const info = await client.getEpochInfo();
80
+ return {
81
+ epoch: BigInt(info.epoch),
82
+ slotIndex: BigInt(info.slotIndex),
83
+ slotsInEpoch: BigInt(info.slotsInEpoch),
84
+ };
85
+ };
86
+ /**
87
+ * The rent-exempt reserve for a 200-byte stake account, in lamports. The new
88
+ * stake account must be funded with this on top of the delegated amount.
89
+ */
90
+ export const fetchSolanaRentReserve = async () => {
91
+ const client = getSolanaClient();
92
+ const lamports = await client.getMinimumBalanceForRentExemption(solanaStakingConfig.stakeStateSize);
93
+ return BigInt(lamports);
94
+ };
95
+ /** Network inflation rate (total) — drives the on-chain APY fallback. */
96
+ export const fetchSolanaInflationRate = async () => {
97
+ const client = getSolanaClient();
98
+ const { total } = await client.getInflationRate();
99
+ return total;
100
+ };
101
+ /**
102
+ * Total SOL supply in lamports — the denominator for the staked fraction in the
103
+ * APY fallback. `getSupply` returns a JSON number that exceeds 2^53, so it is
104
+ * already approximate; kept as `number` (the ratio it feeds only needs ~2dp),
105
+ * not minted into a falsely-exact bigint.
106
+ */
107
+ export const fetchSolanaTotalSupply = async () => {
108
+ const client = getSolanaClient();
109
+ const { value } = await client.getSupply();
110
+ return value.total;
111
+ };
112
+ //# sourceMappingURL=rpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/staking/rpc.ts"],"names":[],"mappings":"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"}
@@ -3,4 +3,13 @@
3
3
  * The toncenter v3 API requires raw addresses.
4
4
  */
5
5
  export declare const tonAddressToRaw: (userFriendlyAddress: string) => string;
6
+ /**
7
+ * Converts a raw TON address (`workchain:hex`) to the bounceable user-friendly
8
+ * form (`EQ…`). Staking-API pool addresses arrive in raw `0:` form, which the
9
+ * signer treats as non-bounceable — sending a deposit non-bounceable risks the
10
+ * pool absorbing (losing) a rejected transfer instead of bouncing it back, so
11
+ * pool destinations MUST be normalized to the bounceable form first. Inputs
12
+ * already in user-friendly form are returned re-encoded as bounceable.
13
+ */
14
+ export declare const tonAddressToBounceable: (address: string) => string;
6
15
  //# sourceMappingURL=address.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/chains/ton/address.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,qBAAqB,MAAM,KAAG,MAM7D,CAAA"}
1
+ {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/chains/ton/address.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,qBAAqB,MAAM,KAAG,MAM7D,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,KAAG,MAIxD,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { Address } from '@ton/core';
1
2
  import { fromBase64 } from '@vultisig/lib-utils/fromBase64';
2
3
  /** Converts base64url encoding to standard base64 so `Buffer.from` can decode it. */
3
4
  const fromBase64Url = (value) => {
@@ -14,4 +15,16 @@ export const tonAddressToRaw = (userFriendlyAddress) => {
14
15
  const hash = decoded.subarray(2, 34).toString('hex');
15
16
  return `${workchain}:${hash}`;
16
17
  };
18
+ /**
19
+ * Converts a raw TON address (`workchain:hex`) to the bounceable user-friendly
20
+ * form (`EQ…`). Staking-API pool addresses arrive in raw `0:` form, which the
21
+ * signer treats as non-bounceable — sending a deposit non-bounceable risks the
22
+ * pool absorbing (losing) a rejected transfer instead of bouncing it back, so
23
+ * pool destinations MUST be normalized to the bounceable form first. Inputs
24
+ * already in user-friendly form are returned re-encoded as bounceable.
25
+ */
26
+ export const tonAddressToBounceable = (address) => {
27
+ const parsed = address.includes(':') ? Address.parseRaw(address) : Address.parse(address);
28
+ return parsed.toString({ bounceable: true, testOnly: false, urlSafe: true });
29
+ };
17
30
  //# sourceMappingURL=address.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"address.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/chains/ton/address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAE3D,qFAAqF;AACrF,MAAM,aAAa,GAAG,CAAC,KAAa,EAAU,EAAE;IAC9C,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAClE,OAAO,UAAU,CAAC,cAAc,CAAC,CAAA;AACnC,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,mBAA2B,EAAU,EAAE;IACrE,MAAM,OAAO,GAAG,aAAa,CAAC,mBAAmB,CAAC,CAAA;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACnE,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEpD,OAAO,GAAG,SAAS,IAAI,IAAI,EAAE,CAAA;AAC/B,CAAC,CAAA"}
1
+ {"version":3,"file":"address.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/chains/ton/address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAE3D,qFAAqF;AACrF,MAAM,aAAa,GAAG,CAAC,KAAa,EAAU,EAAE;IAC9C,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAClE,OAAO,UAAU,CAAC,cAAc,CAAC,CAAA;AACnC,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,mBAA2B,EAAU,EAAE;IACrE,MAAM,OAAO,GAAG,aAAa,CAAC,mBAAmB,CAAC,CAAA;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACnE,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEpD,OAAO,GAAG,SAAS,IAAI,IAAI,EAAE,CAAA;AAC/B,CAAC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,OAAe,EAAU,EAAE;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAEzF,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;AAC9E,CAAC,CAAA"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * tonapi `implementation` values that are genuine **nominator pools** — the
3
+ * only ones the text-comment deposit/withdraw mechanism can stake into.
4
+ * `liquidTF` (Tonstakers) mints a jetton instead and is excluded; unknown
5
+ * implementations are treated as non-nominator (excluded).
6
+ */
7
+ export declare const tonNominatorImplementations: readonly ["whales", "tf"];
8
+ export type TonNominatorImplementation = (typeof tonNominatorImplementations)[number];
9
+ export declare const isTonNominatorImplementation: (implementation: string | undefined) => implementation is TonNominatorImplementation;
10
+ /** Deposit comment for a pool implementation, or `undefined` if unsupported (block the action). */
11
+ export declare const tonStakingDepositComment: (implementation: string | undefined) => string | undefined;
12
+ /** Withdraw comment for a pool implementation, or `undefined` if unsupported (block the action). */
13
+ export declare const tonStakingWithdrawComment: (implementation: string | undefined) => string | undefined;
14
+ /**
15
+ * Whether a memo is a nominator-pool deposit/withdraw comment (`d`/`w`/`Deposit`
16
+ * /`Withdraw`). The signer uses this to force the transfer bounceable: a pool
17
+ * deposit/withdraw sent non-bounceable can be absorbed (lost) by the pool
18
+ * instead of bounced back if rejected.
19
+ */
20
+ export declare const isTonStakingComment: (memo: string | undefined) => boolean;
21
+ /**
22
+ * Processing-commission buffer (nanotons) added on top of a pool's `min_stake`
23
+ * for the minimum acceptable deposit. Depositing exactly the minimum is
24
+ * rejected; the pool needs ~1 TON headroom for its processing commission.
25
+ */
26
+ export declare const tonStakingDepositBuffer = 1000000000n;
27
+ /**
28
+ * Amount (nanotons) accompanying a withdraw message — the pool's 0.2 TON
29
+ * withdraw fee. The pool returns the full staked balance separately; sending
30
+ * more (e.g. 1 TON) fails.
31
+ */
32
+ export declare const tonStakingWithdrawFee = 200000000n;
33
+ /**
34
+ * Conservative network-fee reserve (nanotons ≈ 0.05 TON) held back from the
35
+ * spendable balance when sizing a stake deposit or checking the unstake fee is
36
+ * affordable. Larger than the bare base fee because the text-comment cell adds
37
+ * compute; matches the iOS reserve.
38
+ */
39
+ export declare const tonStakingFeeReserve = 50000000n;
40
+ /**
41
+ * A staking-pool list entry. `address` is the bounceable user-friendly (`EQ…`)
42
+ * pool contract address (normalized from the raw `0:` API form), `apy` is a
43
+ * percentage (e.g. `13.27` = 13.27%), and `minStake` is in nanotons.
44
+ */
45
+ export type TonStakingPool = {
46
+ address: string;
47
+ name: string;
48
+ apy: number;
49
+ minStake: bigint;
50
+ verified: boolean;
51
+ currentNominators?: number;
52
+ maxNominators?: number;
53
+ implementation?: string;
54
+ cycleEnd?: number;
55
+ };
56
+ /** Whether a pool has room for another nominator (pools at capacity reject new stakes). */
57
+ export declare const tonPoolHasCapacity: (pool: TonStakingPool) => boolean;
58
+ /**
59
+ * Whether a pool is a verified nominator pool with capacity — i.e. one the
60
+ * picker should surface and a stake can succeed into.
61
+ */
62
+ export declare const isStakeableTonPool: (pool: TonStakingPool) => boolean;
63
+ /**
64
+ * Fetches all verified TON staking pools from tonapi (`/v2/staking/pools`).
65
+ * Includes every implementation; callers filter to stakeable nominator pools
66
+ * via `isStakeableTonPool`.
67
+ */
68
+ export declare const getTonStakingPools: () => Promise<TonStakingPool[]>;
69
+ /**
70
+ * Computed info for a single pool (`/v2/staking/pool/{address}`). All fields
71
+ * are optional so a partial/changed response degrades gracefully. `apy` is a
72
+ * percentage; `cycleEnd` is the Unix second the current validation cycle ends.
73
+ */
74
+ export type TonStakingPoolInfo = {
75
+ address?: string;
76
+ name?: string;
77
+ apy?: number;
78
+ minStake?: bigint;
79
+ implementation?: string;
80
+ cycleEnd?: number;
81
+ };
82
+ /** Fetches computed pool metadata (name, APY, implementation, cycle end). */
83
+ export declare const getTonStakingPoolInfo: (poolAddress: string) => Promise<TonStakingPoolInfo | undefined>;
84
+ /**
85
+ * An account's position in a nominator pool. All amounts are nanotons. `amount`
86
+ * is the active stake; `pendingDeposit` is a just-placed stake awaiting the
87
+ * next validation cycle; `pendingWithdraw`/`readyWithdraw` indicate an
88
+ * in-progress withdrawal (funds locked until the cycle ends). `pool` is the
89
+ * bounceable user-friendly (`EQ…`) pool address (normalized from raw `0:`).
90
+ */
91
+ export type TonNominatorPosition = {
92
+ pool: string;
93
+ amount: bigint;
94
+ pendingDeposit: bigint;
95
+ pendingWithdraw: bigint;
96
+ readyWithdraw: bigint;
97
+ };
98
+ /**
99
+ * Fetches an account's nominator-pool positions
100
+ * (`/v2/staking/nominator/{accountId}/pools`) — the authoritative source for
101
+ * staked positions. `accountId` accepts the user-friendly wallet address.
102
+ */
103
+ export declare const getTonNominatorPools: (accountId: string) => Promise<TonNominatorPosition[]>;
104
+ //# sourceMappingURL=staking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staking.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/chains/ton/staking.ts"],"names":[],"mappings":"AAYA;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,2BAA4B,CAAA;AAEpE,MAAM,MAAM,0BAA0B,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAA;AAErF,eAAO,MAAM,4BAA4B,GACvC,gBAAgB,MAAM,GAAG,SAAS,KACjC,cAAc,IAAI,0BAC4E,CAAA;AAqBjG,mGAAmG;AACnG,eAAO,MAAM,wBAAwB,GAAI,gBAAgB,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SACe,CAAA;AAEtG,oGAAoG;AACpG,eAAO,MAAM,yBAAyB,GAAI,gBAAgB,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SACe,CAAA;AAOvG;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,GAAG,SAAS,KAAG,OAAwD,CAAA;AAEvH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,cAAiB,CAAA;AAErD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,aAAe,CAAA;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,YAAc,CAAA;AAc/C;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAiBD,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,GAAI,MAAM,cAAc,KAAG,OAMzD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,cAAc,KAAG,OACsC,CAAA;AAEhG;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,cAAc,EAAE,CAKnE,CAAA;AAWD;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,qBAAqB,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAavG,CAAA;AAUD;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,oBAAoB,EAAE,CAW5F,CAAA"}
@@ -0,0 +1,137 @@
1
+ import { queryUrl } from '@vultisig/lib-utils/query/queryUrl';
2
+ import { tonAddressToBounceable } from './address.js';
3
+ /**
4
+ * Public TonAPI host. The staking endpoints (`/v2/staking/*`) are served
5
+ * exclusively by `tonapi.io` — the Vultisig `/ton` proxy fronts toncenter v3,
6
+ * which has no staking routes — so we hit tonapi.io directly. The extension's
7
+ * wildcard https host permission covers it.
8
+ */
9
+ const tonApiPublicUrl = 'https://tonapi.io';
10
+ /**
11
+ * tonapi `implementation` values that are genuine **nominator pools** — the
12
+ * only ones the text-comment deposit/withdraw mechanism can stake into.
13
+ * `liquidTF` (Tonstakers) mints a jetton instead and is excluded; unknown
14
+ * implementations are treated as non-nominator (excluded).
15
+ */
16
+ export const tonNominatorImplementations = ['whales', 'tf'];
17
+ export const isTonNominatorImplementation = (implementation) => !!implementation && tonNominatorImplementations.includes(implementation);
18
+ /**
19
+ * The deposit/withdraw text comments a TON nominator-pool contract expects.
20
+ * Each pool *implementation* uses a DIFFERENT word — sending the wrong one is
21
+ * rejected on-chain (exit code 72). These are contract protocol tokens, NOT
22
+ * user-facing UI: never translate them.
23
+ *
24
+ * The Whales pool repo README's "Stake" is stale and rejected by the live
25
+ * pools; the verified on-chain word is "Deposit".
26
+ */
27
+ const tonStakingDepositComments = {
28
+ tf: 'd',
29
+ whales: 'Deposit',
30
+ };
31
+ const tonStakingWithdrawComments = {
32
+ tf: 'w',
33
+ whales: 'Withdraw',
34
+ };
35
+ /** Deposit comment for a pool implementation, or `undefined` if unsupported (block the action). */
36
+ export const tonStakingDepositComment = (implementation) => isTonNominatorImplementation(implementation) ? tonStakingDepositComments[implementation] : undefined;
37
+ /** Withdraw comment for a pool implementation, or `undefined` if unsupported (block the action). */
38
+ export const tonStakingWithdrawComment = (implementation) => isTonNominatorImplementation(implementation) ? tonStakingWithdrawComments[implementation] : undefined;
39
+ const tonStakingComments = new Set([
40
+ ...Object.values(tonStakingDepositComments),
41
+ ...Object.values(tonStakingWithdrawComments),
42
+ ]);
43
+ /**
44
+ * Whether a memo is a nominator-pool deposit/withdraw comment (`d`/`w`/`Deposit`
45
+ * /`Withdraw`). The signer uses this to force the transfer bounceable: a pool
46
+ * deposit/withdraw sent non-bounceable can be absorbed (lost) by the pool
47
+ * instead of bounced back if rejected.
48
+ */
49
+ export const isTonStakingComment = (memo) => !!memo && tonStakingComments.has(memo.trim());
50
+ /**
51
+ * Processing-commission buffer (nanotons) added on top of a pool's `min_stake`
52
+ * for the minimum acceptable deposit. Depositing exactly the minimum is
53
+ * rejected; the pool needs ~1 TON headroom for its processing commission.
54
+ */
55
+ export const tonStakingDepositBuffer = 1000000000n;
56
+ /**
57
+ * Amount (nanotons) accompanying a withdraw message — the pool's 0.2 TON
58
+ * withdraw fee. The pool returns the full staked balance separately; sending
59
+ * more (e.g. 1 TON) fails.
60
+ */
61
+ export const tonStakingWithdrawFee = 200000000n;
62
+ /**
63
+ * Conservative network-fee reserve (nanotons ≈ 0.05 TON) held back from the
64
+ * spendable balance when sizing a stake deposit or checking the unstake fee is
65
+ * affordable. Larger than the bare base fee because the text-comment cell adds
66
+ * compute; matches the iOS reserve.
67
+ */
68
+ export const tonStakingFeeReserve = 50000000n;
69
+ const mapPoolEntry = (entry) => ({
70
+ // Normalize to the bounceable `EQ…` form at the boundary so no caller can
71
+ // build a staking transfer to a raw/non-bounceable destination (which the
72
+ // pool would absorb instead of bouncing back on rejection).
73
+ address: tonAddressToBounceable(entry.address),
74
+ name: entry.name,
75
+ apy: entry.apy,
76
+ minStake: BigInt(Math.trunc(entry.min_stake)),
77
+ verified: entry.verified,
78
+ currentNominators: entry.current_nominators,
79
+ maxNominators: entry.max_nominators,
80
+ implementation: entry.implementation,
81
+ cycleEnd: entry.cycle_end,
82
+ });
83
+ /** Whether a pool has room for another nominator (pools at capacity reject new stakes). */
84
+ export const tonPoolHasCapacity = (pool) => {
85
+ const { currentNominators, maxNominators } = pool;
86
+ if (currentNominators === undefined || maxNominators === undefined || maxNominators <= 0) {
87
+ return true;
88
+ }
89
+ return currentNominators < maxNominators;
90
+ };
91
+ /**
92
+ * Whether a pool is a verified nominator pool with capacity — i.e. one the
93
+ * picker should surface and a stake can succeed into.
94
+ */
95
+ export const isStakeableTonPool = (pool) => pool.verified && isTonNominatorImplementation(pool.implementation) && tonPoolHasCapacity(pool);
96
+ /**
97
+ * Fetches all verified TON staking pools from tonapi (`/v2/staking/pools`).
98
+ * Includes every implementation; callers filter to stakeable nominator pools
99
+ * via `isStakeableTonPool`.
100
+ */
101
+ export const getTonStakingPools = async () => {
102
+ const url = `${tonApiPublicUrl}/v2/staking/pools?include_unverified=false`;
103
+ const { pools } = await queryUrl(url);
104
+ return pools.map(mapPoolEntry);
105
+ };
106
+ /** Fetches computed pool metadata (name, APY, implementation, cycle end). */
107
+ export const getTonStakingPoolInfo = async (poolAddress) => {
108
+ const url = `${tonApiPublicUrl}/v2/staking/pool/${encodeURIComponent(poolAddress)}`;
109
+ const { pool } = await queryUrl(url);
110
+ if (!pool)
111
+ return undefined;
112
+ return {
113
+ address: pool.address ? tonAddressToBounceable(pool.address) : undefined,
114
+ name: pool.name,
115
+ apy: pool.apy,
116
+ minStake: pool.min_stake !== undefined ? BigInt(Math.trunc(pool.min_stake)) : undefined,
117
+ implementation: pool.implementation,
118
+ cycleEnd: pool.cycle_end,
119
+ };
120
+ };
121
+ /**
122
+ * Fetches an account's nominator-pool positions
123
+ * (`/v2/staking/nominator/{accountId}/pools`) — the authoritative source for
124
+ * staked positions. `accountId` accepts the user-friendly wallet address.
125
+ */
126
+ export const getTonNominatorPools = async (accountId) => {
127
+ const url = `${tonApiPublicUrl}/v2/staking/nominator/${encodeURIComponent(accountId)}/pools`;
128
+ const { pools } = await queryUrl(url);
129
+ return pools.map(position => ({
130
+ pool: tonAddressToBounceable(position.pool),
131
+ amount: BigInt(Math.trunc(position.amount)),
132
+ pendingDeposit: BigInt(Math.trunc(position.pending_deposit)),
133
+ pendingWithdraw: BigInt(Math.trunc(position.pending_withdraw)),
134
+ readyWithdraw: BigInt(Math.trunc(position.ready_withdraw)),
135
+ }));
136
+ };
137
+ //# sourceMappingURL=staking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staking.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/chains/ton/staking.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { EvmChain } from '@vultisig/core-chain/Chain';
2
+ import { AccountCoinKey } from '@vultisig/core-chain/coin/AccountCoin';
3
+ import { Address } from 'viem';
4
+ export type GetEvmChainBalancesInput = {
5
+ chain: EvmChain;
6
+ address: Address;
7
+ coins: AccountCoinKey<EvmChain>[];
8
+ };
9
+ export type EvmChainBalances = Record<string, bigint>;
10
+ export declare const getEvmChainBalances: (input: GetEvmChainBalancesInput) => Promise<EvmChainBalances>;
11
+ //# sourceMappingURL=getEvmChainBalances.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getEvmChainBalances.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/balance/getEvmChainBalances.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAErD,OAAO,EAAE,cAAc,EAA0B,MAAM,uCAAuC,CAAA;AAE9F,OAAO,EAAE,OAAO,EAAsB,MAAM,MAAM,CAAA;AAMlD,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,QAAQ,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAkBrD,eAAO,MAAM,mBAAmB,GAAU,OAAO,wBAAwB,KAAG,OAAO,CAAC,gBAAgB,CAiDnG,CAAA"}
@@ -0,0 +1,57 @@
1
+ import { getEvmClient } from '@vultisig/core-chain/chains/evm/client';
2
+ import { accountCoinKeyToString } from '@vultisig/core-chain/coin/AccountCoin';
3
+ import { isFeeCoin } from '@vultisig/core-chain/coin/utils/isFeeCoin';
4
+ import { erc20Abi, parseAbi } from 'viem';
5
+ import { getEvmCoinBalance } from './resolvers/evm.js';
6
+ const multicall3Abi = parseAbi(['function getEthBalance(address addr) view returns (uint256)']);
7
+ const getFallbackBalances = async ({ chain, address, coins }) => {
8
+ const entries = await Promise.all(coins.map(async (coin) => {
9
+ const input = { ...coin, chain, address };
10
+ try {
11
+ return [accountCoinKeyToString(input), await getEvmCoinBalance(input)];
12
+ }
13
+ catch {
14
+ return [accountCoinKeyToString(input), 0n];
15
+ }
16
+ }));
17
+ return Object.fromEntries(entries);
18
+ };
19
+ export const getEvmChainBalances = async (input) => {
20
+ const { chain, address, coins } = input;
21
+ if (coins.length === 0) {
22
+ return {};
23
+ }
24
+ const publicClient = getEvmClient(chain);
25
+ const multicall3Address = publicClient.chain?.contracts?.multicall3?.address;
26
+ if (!multicall3Address) {
27
+ return getFallbackBalances(input);
28
+ }
29
+ const contracts = coins.map(coin => isFeeCoin(coin)
30
+ ? {
31
+ address: multicall3Address,
32
+ abi: multicall3Abi,
33
+ functionName: 'getEthBalance',
34
+ args: [address],
35
+ }
36
+ : {
37
+ address: coin.id,
38
+ abi: erc20Abi,
39
+ functionName: 'balanceOf',
40
+ args: [address],
41
+ });
42
+ const results = await publicClient
43
+ .multicall({
44
+ allowFailure: true,
45
+ contracts,
46
+ })
47
+ .catch(() => undefined);
48
+ if (!results) {
49
+ return getFallbackBalances(input);
50
+ }
51
+ return Object.fromEntries(coins.map((coin, index) => {
52
+ const result = results[index];
53
+ const amount = result?.status === 'success' ? BigInt(result.result) : 0n;
54
+ return [accountCoinKeyToString({ ...coin, chain, address }), amount];
55
+ }));
56
+ };
57
+ //# sourceMappingURL=getEvmChainBalances.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getEvmChainBalances.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/balance/getEvmChainBalances.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export declare const generalSwapProviders: readonly ["1inch", "li.fi", "kyber", "swapkit", "cowswap"];
1
+ export declare const generalSwapProviders: readonly ["1inch", "li.fi", "kyber", "swapkit", "cowswap", "jupiter"];
2
2
  export type GeneralSwapProvider = (typeof generalSwapProviders)[number];
3
3
  export declare const generalSwapProviderName: Record<GeneralSwapProvider, string>;
4
4
  //# sourceMappingURL=GeneralSwapProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GeneralSwapProvider.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapProvider.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,4DAA6D,CAAA;AAE9F,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvE,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAMvE,CAAA"}
1
+ {"version":3,"file":"GeneralSwapProvider.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapProvider.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,uEAAwE,CAAA;AAEzG,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvE,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAOvE,CAAA"}
@@ -1,9 +1,10 @@
1
- export const generalSwapProviders = ['1inch', 'li.fi', 'kyber', 'swapkit', 'cowswap'];
1
+ export const generalSwapProviders = ['1inch', 'li.fi', 'kyber', 'swapkit', 'cowswap', 'jupiter'];
2
2
  export const generalSwapProviderName = {
3
3
  '1inch': '1Inch',
4
4
  'li.fi': 'LI.FI',
5
5
  kyber: 'KyberSwap',
6
6
  swapkit: 'SwapKit',
7
7
  cowswap: 'CowSwap',
8
+ jupiter: 'Jupiter',
8
9
  };
9
10
  //# sourceMappingURL=GeneralSwapProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GeneralSwapProvider.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapProvider.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAU,CAAA;AAI9F,MAAM,CAAC,MAAM,uBAAuB,GAAwC;IAC1E,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,WAAW;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACnB,CAAA"}
1
+ {"version":3,"file":"GeneralSwapProvider.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapProvider.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAU,CAAA;AAIzG,MAAM,CAAC,MAAM,uBAAuB,GAAwC;IAC1E,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,WAAW;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACnB,CAAA"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Jupiter is a Solana-only, same-chain aggregator. It can route SOL↔SPL and
3
+ * SPL↔SPL pairs that stay on Solana, and nothing else — there is no cross-chain
4
+ * Jupiter route. `findSwapQuote` therefore only offers Jupiter when both legs
5
+ * are on Solana.
6
+ */
7
+ export declare const jupiterSwapEnabledChains: readonly [import("@vultisig/core-chain/Chain").OtherChain.Solana];
8
+ export type JupiterSwapEnabledChain = (typeof jupiterSwapEnabledChains)[number];
9
+ //# sourceMappingURL=JupiterSwapEnabledChains.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JupiterSwapEnabledChains.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/swap/general/jupiter/JupiterSwapEnabledChains.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,mEAA0B,CAAA;AAE/D,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAA"}
@@ -0,0 +1,9 @@
1
+ import { Chain } from '@vultisig/core-chain/Chain';
2
+ /**
3
+ * Jupiter is a Solana-only, same-chain aggregator. It can route SOL↔SPL and
4
+ * SPL↔SPL pairs that stay on Solana, and nothing else — there is no cross-chain
5
+ * Jupiter route. `findSwapQuote` therefore only offers Jupiter when both legs
6
+ * are on Solana.
7
+ */
8
+ export const jupiterSwapEnabledChains = [Chain.Solana];
9
+ //# sourceMappingURL=JupiterSwapEnabledChains.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JupiterSwapEnabledChains.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/swap/general/jupiter/JupiterSwapEnabledChains.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAU,CAAA"}
@@ -0,0 +1,25 @@
1
+ import { AccountCoin } from '@vultisig/core-chain/coin/AccountCoin';
2
+ import { GeneralSwapQuote } from '@vultisig/core-chain/swap/general/GeneralSwapQuote';
3
+ import { JupiterSwapEnabledChain } from '@vultisig/core-chain/swap/general/jupiter/JupiterSwapEnabledChains';
4
+ import { TransferDirection } from '@vultisig/lib-utils/TransferDirection';
5
+ type Input = Record<TransferDirection, AccountCoin<JupiterSwapEnabledChain>> & {
6
+ amount: bigint;
7
+ /** VULT-scaled affiliate fee in bps. `0` disables the platform fee entirely. */
8
+ affiliateBps?: number;
9
+ /** Slippage tolerance in bps (e.g. 50 = 0.5%). Defaults to 50. */
10
+ slippageBps?: number;
11
+ };
12
+ /**
13
+ * Fetch a Solana same-chain swap quote from Jupiter and build the signed-tx
14
+ * payload the keysign pipeline expects.
15
+ *
16
+ * Affiliate fee: when `affiliateBps > 0`, `platformFeeBps` is sent on the quote.
17
+ * The fee ATA (output mint, owner = `jupiterFeeOwnerAddress`) is derived, passed
18
+ * to `/swap` as `feeAccount`, and an idempotent create instruction is prepended
19
+ * to the returned transaction only when the quote actually returns a non-zero
20
+ * `platformFee.amount`. When `affiliateBps` is 0 (e.g. an Ultimate-tier VULT
21
+ * holder) or Jupiter floors the fee to zero, no fee account is touched.
22
+ */
23
+ export declare const getJupiterSwapQuote: ({ from, to, amount, affiliateBps, slippageBps, }: Input) => Promise<GeneralSwapQuote>;
24
+ export {};
25
+ //# sourceMappingURL=getJupiterSwapQuote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getJupiterSwapQuote.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/swap/general/jupiter/api/getJupiterSwapQuote.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oDAAoD,CAAA;AAErF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oEAAoE,CAAA;AAC5G,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAUzE,KAAK,KAAK,GAAG,MAAM,CAAC,iBAAiB,EAAE,WAAW,CAAC,uBAAuB,CAAC,CAAC,GAAG;IAC7E,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AA2CD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,GAAU,kDAMvC,KAAK,KAAG,OAAO,CAAC,gBAAgB,CAuFlC,CAAA"}