@vultisig/core-chain 2.37.0 → 2.38.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 (74) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/chains/solana/kamino/KaminoServiceError.d.ts +63 -0
  3. package/dist/chains/solana/kamino/KaminoServiceError.d.ts.map +1 -0
  4. package/dist/chains/solana/kamino/KaminoServiceError.js +29 -0
  5. package/dist/chains/solana/kamino/KaminoServiceError.js.map +1 -0
  6. package/dist/chains/solana/kamino/amount.d.ts +141 -0
  7. package/dist/chains/solana/kamino/amount.d.ts.map +1 -0
  8. package/dist/chains/solana/kamino/amount.js +156 -0
  9. package/dist/chains/solana/kamino/amount.js.map +1 -0
  10. package/dist/chains/solana/kamino/api.d.ts +20 -0
  11. package/dist/chains/solana/kamino/api.d.ts.map +1 -0
  12. package/dist/chains/solana/kamino/api.js +59 -0
  13. package/dist/chains/solana/kamino/api.js.map +1 -0
  14. package/dist/chains/solana/kamino/baseUnits.d.ts +23 -0
  15. package/dist/chains/solana/kamino/baseUnits.d.ts.map +1 -0
  16. package/dist/chains/solana/kamino/baseUnits.js +30 -0
  17. package/dist/chains/solana/kamino/baseUnits.js.map +1 -0
  18. package/dist/chains/solana/kamino/config.d.ts +27 -0
  19. package/dist/chains/solana/kamino/config.d.ts.map +1 -0
  20. package/dist/chains/solana/kamino/config.js +27 -0
  21. package/dist/chains/solana/kamino/config.js.map +1 -0
  22. package/dist/chains/solana/kamino/decimal.d.ts +24 -0
  23. package/dist/chains/solana/kamino/decimal.d.ts.map +1 -0
  24. package/dist/chains/solana/kamino/decimal.js +52 -0
  25. package/dist/chains/solana/kamino/decimal.js.map +1 -0
  26. package/dist/chains/solana/kamino/models.d.ts +148 -0
  27. package/dist/chains/solana/kamino/models.d.ts.map +1 -0
  28. package/dist/chains/solana/kamino/models.js +2 -0
  29. package/dist/chains/solana/kamino/models.js.map +1 -0
  30. package/dist/chains/solana/kamino/position.d.ts +79 -0
  31. package/dist/chains/solana/kamino/position.d.ts.map +1 -0
  32. package/dist/chains/solana/kamino/position.js +52 -0
  33. package/dist/chains/solana/kamino/position.js.map +1 -0
  34. package/dist/chains/solana/kamino/rate.d.ts +57 -0
  35. package/dist/chains/solana/kamino/rate.d.ts.map +1 -0
  36. package/dist/chains/solana/kamino/rate.js +88 -0
  37. package/dist/chains/solana/kamino/rate.js.map +1 -0
  38. package/dist/chains/solana/kamino/registry.d.ts +70 -0
  39. package/dist/chains/solana/kamino/registry.d.ts.map +1 -0
  40. package/dist/chains/solana/kamino/registry.js +67 -0
  41. package/dist/chains/solana/kamino/registry.js.map +1 -0
  42. package/dist/chains/solana/kamino/tx/actions.d.ts +22 -0
  43. package/dist/chains/solana/kamino/tx/actions.d.ts.map +1 -0
  44. package/dist/chains/solana/kamino/tx/actions.js +85 -0
  45. package/dist/chains/solana/kamino/tx/actions.js.map +1 -0
  46. package/dist/chains/solana/kamino/tx/computeBudget.d.ts +66 -0
  47. package/dist/chains/solana/kamino/tx/computeBudget.d.ts.map +1 -0
  48. package/dist/chains/solana/kamino/tx/computeBudget.js +73 -0
  49. package/dist/chains/solana/kamino/tx/computeBudget.js.map +1 -0
  50. package/dist/chains/solana/kamino/tx/decode.d.ts +121 -0
  51. package/dist/chains/solana/kamino/tx/decode.d.ts.map +1 -0
  52. package/dist/chains/solana/kamino/tx/decode.js +458 -0
  53. package/dist/chains/solana/kamino/tx/decode.js.map +1 -0
  54. package/dist/chains/solana/kamino/tx/instructions.d.ts +260 -0
  55. package/dist/chains/solana/kamino/tx/instructions.d.ts.map +1 -0
  56. package/dist/chains/solana/kamino/tx/instructions.js +256 -0
  57. package/dist/chains/solana/kamino/tx/instructions.js.map +1 -0
  58. package/dist/chains/solana/kamino/tx/sequence.d.ts +123 -0
  59. package/dist/chains/solana/kamino/tx/sequence.d.ts.map +1 -0
  60. package/dist/chains/solana/kamino/tx/sequence.js +235 -0
  61. package/dist/chains/solana/kamino/tx/sequence.js.map +1 -0
  62. package/dist/chains/solana/kamino/tx/validate.d.ts +138 -0
  63. package/dist/chains/solana/kamino/tx/validate.d.ts.map +1 -0
  64. package/dist/chains/solana/kamino/tx/validate.js +542 -0
  65. package/dist/chains/solana/kamino/tx/validate.js.map +1 -0
  66. package/dist/chains/solana/kamino/tx/wire.d.ts +107 -0
  67. package/dist/chains/solana/kamino/tx/wire.d.ts.map +1 -0
  68. package/dist/chains/solana/kamino/tx/wire.js +274 -0
  69. package/dist/chains/solana/kamino/tx/wire.js.map +1 -0
  70. package/dist/chains/solana/kamino/vaultInfo.d.ts +17 -0
  71. package/dist/chains/solana/kamino/vaultInfo.d.ts.map +1 -0
  72. package/dist/chains/solana/kamino/vaultInfo.js +150 -0
  73. package/dist/chains/solana/kamino/vaultInfo.js.map +1 -0
  74. package/package.json +91 -1
@@ -0,0 +1,235 @@
1
+ import { computeBudgetDiscriminators, createIdempotentAtaDiscriminator, hasAnchorDiscriminator, isAttributionMemoData, kaminoDiscriminators, systemTransferDiscriminator, tokenCloseAccountDiscriminator, tokenSyncNativeDiscriminator, } from './instructions.js';
2
+ /**
3
+ * The instruction shapes each Kamino operation produces, and the walk that
4
+ * matches a transaction against them.
5
+ *
6
+ * Shared by the two places that need it, because they must agree on what a
7
+ * Kamino transaction is *allowed to contain*: the validator runs it on the
8
+ * initiating device before signing, followed by account-identity checks that
9
+ * need the lookup tables resolved; the decoder runs it on ANY device, offline,
10
+ * before claiming to describe a transaction. Without it the decode would read
11
+ * one recognised instruction and say nothing about the rest — so a transfer
12
+ * riding alongside a plausible deposit would be summarised as "Deposit
13
+ * 1 USDC", which is worse than showing nothing at all.
14
+ *
15
+ * A step matches on the program and the instruction discriminator only. Both
16
+ * are readable without a lookup table (a v0 message's program ids are always
17
+ * static keys), which is what lets the offline decode use the same template
18
+ * as the online validator. Everything else about an instruction is checked
19
+ * after it has been matched, so a wrong ACCOUNT is a refusal rather than a
20
+ * silent failure to match.
21
+ */
22
+ export const kaminoInstructionKinds = [
23
+ 'computeUnitLimit',
24
+ 'computeUnitPrice',
25
+ 'createTokenAccount',
26
+ 'wrapSolTransfer',
27
+ 'syncNative',
28
+ 'closeTokenAccount',
29
+ 'kvaultDeposit',
30
+ 'kvaultWithdraw',
31
+ 'farmsInitializeUser',
32
+ 'farmsStake',
33
+ 'farmsUnstake',
34
+ 'farmsWithdrawUnstakedDeposits',
35
+ 'attributionMemo',
36
+ ];
37
+ /** Human-readable step names, used in refusal messages. */
38
+ export const kaminoInstructionKindName = {
39
+ computeUnitLimit: 'compute unit limit',
40
+ computeUnitPrice: 'compute unit price',
41
+ createTokenAccount: 'create associated token account',
42
+ wrapSolTransfer: 'SOL wrap transfer',
43
+ syncNative: 'wrapped SOL sync',
44
+ closeTokenAccount: 'close token account',
45
+ kvaultDeposit: 'vault deposit',
46
+ kvaultWithdraw: 'vault withdraw',
47
+ farmsInitializeUser: 'farm user initialization',
48
+ farmsStake: 'farm stake',
49
+ farmsUnstake: 'farm unstake',
50
+ farmsWithdrawUnstakedDeposits: 'farm unstaked share withdrawal',
51
+ attributionMemo: 'attribution memo',
52
+ };
53
+ /**
54
+ * The shape `operation` produces against a vault with these properties,
55
+ * verified by decoding transactions the Kamino API built and simulating them
56
+ * on mainnet.
57
+ *
58
+ * Optional steps are the ones whose absence cannot cost the user anything —
59
+ * an idempotent account creation that was already done, a farm user that
60
+ * already exists, a token account that stays open. Everything that decides
61
+ * where money moves is required, and anything not listed at all is refused.
62
+ */
63
+ export const expectedKaminoSequence = ({ operation, isWrappedSolVault, hasFarm, hasPriorityFee, hasAttributionMemo, farmUnstake, }) => {
64
+ const steps = [];
65
+ const step = (kind, isRequired, isRepeatable, pairedWith) => steps.push({ kind, isRequired, isRepeatable, pairedWith });
66
+ if (hasPriorityFee) {
67
+ step('computeUnitLimit', true, false);
68
+ step('computeUnitPrice', true, false);
69
+ }
70
+ if (operation === 'deposit') {
71
+ step('createTokenAccount', false, true);
72
+ if (isWrappedSolVault) {
73
+ step('wrapSolTransfer', true, false);
74
+ step('syncNative', true, false);
75
+ step('createTokenAccount', false, true);
76
+ }
77
+ step('kvaultDeposit', true, false);
78
+ if (hasFarm) {
79
+ // Only the user's farm state may already exist. The stake itself is
80
+ // what makes the shares the position the app then reads, so a deposit
81
+ // that omits it is not the deposit that was requested.
82
+ step('farmsInitializeUser', false, false);
83
+ step('farmsStake', true, false);
84
+ }
85
+ }
86
+ else {
87
+ // The share account the released shares land in, created first because
88
+ // the two farms instructions below need it to exist.
89
+ step('createTokenAccount', false, true);
90
+ if (hasFarm && farmUnstake !== 'forbidden') {
91
+ // BOTH farms instructions, and both BEFORE the vault withdraw — the
92
+ // shares have to be out of the farm and in the user's own account
93
+ // before anything can burn them. They appear together or not at all;
94
+ // `farmUnstake` decides which of the two transaction shapes this is
95
+ // supposed to be, so a caller that knows gets a REQUIRED pair and a
96
+ // caller that cannot know gets an optional one — never a silent
97
+ // "either is fine" for the device that could have checked.
98
+ const required = farmUnstake === 'required';
99
+ step('farmsUnstake', required, false, 'farmsWithdrawUnstakedDeposits');
100
+ step('farmsWithdrawUnstakedDeposits', required, false, 'farmsUnstake');
101
+ step('createTokenAccount', false, true);
102
+ }
103
+ step('kvaultWithdraw', true, false);
104
+ // Emptied token accounts, closed so their rent comes back. REPEATABLE,
105
+ // because a full wrapped-SOL withdraw carries two: the payout account and
106
+ // the now-empty share account. REQUIRED on the wrapped-SOL vault, where
107
+ // closing the payout account is what unwraps wSOL into the native SOL the
108
+ // screen says the user receives; optional elsewhere.
109
+ step('closeTokenAccount', isWrappedSolVault, true);
110
+ }
111
+ // Last, because that is where the injector appends it: the memo records who
112
+ // originated the transaction and takes no part in what it does.
113
+ if (hasAttributionMemo) {
114
+ step('attributionMemo', true, false);
115
+ }
116
+ return steps;
117
+ };
118
+ /**
119
+ * The kind of instruction this program and payload are, or `undefined` when
120
+ * it is none the template knows. Program and discriminator only — see the
121
+ * module doc for why.
122
+ */
123
+ export const kaminoInstructionKind = (program, data) => {
124
+ if (!program)
125
+ return undefined;
126
+ switch (program) {
127
+ case 'computeBudget':
128
+ if (data[0] === computeBudgetDiscriminators.setUnitLimit)
129
+ return 'computeUnitLimit';
130
+ if (data[0] === computeBudgetDiscriminators.setUnitPrice)
131
+ return 'computeUnitPrice';
132
+ return undefined;
133
+ case 'associatedToken':
134
+ return data[0] === createIdempotentAtaDiscriminator ? 'createTokenAccount' : undefined;
135
+ case 'system':
136
+ return data.length >= 4 && systemTransferDiscriminator.every((byte, index) => data[index] === byte)
137
+ ? 'wrapSolTransfer'
138
+ : undefined;
139
+ case 'token':
140
+ case 'token2022':
141
+ if (data.length === 1 && data[0] === tokenSyncNativeDiscriminator)
142
+ return 'syncNative';
143
+ if (data.length === 1 && data[0] === tokenCloseAccountDiscriminator)
144
+ return 'closeTokenAccount';
145
+ return undefined;
146
+ case 'kvault':
147
+ if (hasAnchorDiscriminator(data, kaminoDiscriminators.kvaultDeposit))
148
+ return 'kvaultDeposit';
149
+ // TWO discriminators, one kind: `withdraw` and `withdraw_from_available`
150
+ // are the same withdraw — same `u64` share argument, same authority,
151
+ // same share account burned, same payout account credited — and which
152
+ // one the builder emits says only whether the vault's liquid buffer
153
+ // covered the request. That is a fact about the vault's balance sheet,
154
+ // not about what the user is being asked to approve. They may share the
155
+ // account map because the IDL declares `withdraw`'s account list as
156
+ // `withdraw_from_available`'s accounts followed by the reserve group.
157
+ if (hasAnchorDiscriminator(data, kaminoDiscriminators.kvaultWithdraw) ||
158
+ hasAnchorDiscriminator(data, kaminoDiscriminators.kvaultWithdrawFromAvailable)) {
159
+ return 'kvaultWithdraw';
160
+ }
161
+ return undefined;
162
+ case 'memo':
163
+ // The tag is matched WHOLE, not as a prefix. A memo is free-form bytes,
164
+ // so the tag followed by anything else is a different memo — and the
165
+ // one thing this app is willing to sign under the Memo program is its
166
+ // own attribution tag, exactly.
167
+ return isAttributionMemoData(data) ? 'attributionMemo' : undefined;
168
+ case 'farms':
169
+ if (hasAnchorDiscriminator(data, kaminoDiscriminators.farmsInitializeUser))
170
+ return 'farmsInitializeUser';
171
+ if (hasAnchorDiscriminator(data, kaminoDiscriminators.farmsStake))
172
+ return 'farmsStake';
173
+ if (hasAnchorDiscriminator(data, kaminoDiscriminators.farmsUnstake))
174
+ return 'farmsUnstake';
175
+ if (hasAnchorDiscriminator(data, kaminoDiscriminators.farmsWithdrawUnstakedDeposits)) {
176
+ return 'farmsWithdrawUnstakedDeposits';
177
+ }
178
+ return undefined;
179
+ }
180
+ };
181
+ /**
182
+ * Walks `steps` and `kinds` together. A step that does not match is skipped
183
+ * only when it is optional; an instruction left over at the end has no place
184
+ * in this operation at all.
185
+ *
186
+ * `kinds` holds one entry per instruction, in order, `undefined` for an
187
+ * instruction whose program is not allow-listed or whose discriminator is not
188
+ * one the template names.
189
+ */
190
+ export const matchKaminoSequence = (kinds, steps) => {
191
+ const matched = [];
192
+ let cursor = 0;
193
+ const matches = (kind, position) => position < kinds.length && kinds[position] === kind;
194
+ for (const step of steps) {
195
+ if (step.isRepeatable) {
196
+ // A repeatable step consumes as many as it finds — and if it is also
197
+ // REQUIRED it has to find at least one. Skipping that check because the
198
+ // loop already ran is how "one or more" silently becomes "zero or
199
+ // more": the wrapped-SOL withdraw's close is both, and without this its
200
+ // requirement would not exist.
201
+ let consumed = 0;
202
+ while (matches(step.kind, cursor)) {
203
+ matched.push(step.kind);
204
+ cursor += 1;
205
+ consumed += 1;
206
+ }
207
+ if (step.isRequired && consumed === 0) {
208
+ return { mismatch: { missingInstruction: kaminoInstructionKindName[step.kind] } };
209
+ }
210
+ continue;
211
+ }
212
+ if (matches(step.kind, cursor)) {
213
+ matched.push(step.kind);
214
+ cursor += 1;
215
+ }
216
+ else if (step.isRequired) {
217
+ return { mismatch: { missingInstruction: kaminoInstructionKindName[step.kind] } };
218
+ }
219
+ }
220
+ if (cursor !== kinds.length) {
221
+ return { mismatch: { unexpectedInstruction: { index: cursor } } };
222
+ }
223
+ // Paired steps, last: a half-operation is a refusal even when both of its
224
+ // halves were individually optional — either the transaction releases
225
+ // shares from the farm and moves them, or it does neither.
226
+ for (const step of steps) {
227
+ if (!step.pairedWith)
228
+ continue;
229
+ if (matched.includes(step.kind) !== matched.includes(step.pairedWith)) {
230
+ return { mismatch: { incompleteInstructionPair: kaminoInstructionKindName[step.kind] } };
231
+ }
232
+ }
233
+ return { matched };
234
+ };
235
+ //# sourceMappingURL=sequence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sequence.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/kamino/tx/sequence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ import { VersionedTransaction } from '@solana/web3.js';
2
+ import { KaminoShareAmount, KaminoTokenAmount } from '../amount.js';
3
+ import { KaminoVaultInfo } from '../models.js';
4
+ /**
5
+ * A withdraw request, split the way the transaction that answers it is built.
6
+ *
7
+ * One type rather than a share amount plus a loose second parameter, because
8
+ * the split is not optional information: the withdraw endpoint builds a plain
9
+ * transaction when the request fits inside the shares already in the user's
10
+ * own account, and one with `farms::unstake` and
11
+ * `farms::withdraw_unstaked_deposits` in front when it does not. Which of
12
+ * those two it will be is decided entirely by `shares` against
13
+ * `unstakedShares`, so a caller that could not state the split could not say
14
+ * which transaction it was expecting, and would have to accept either.
15
+ */
16
+ export type KaminoWithdrawRequest = {
17
+ /** Shares the vault withdraw burns — the `u64` in the instruction. */
18
+ shares: KaminoShareAmount;
19
+ /**
20
+ * Shares already sitting in the user's share account when the position was
21
+ * read — the part a withdraw spends without touching the farm.
22
+ */
23
+ unstakedShares: KaminoShareAmount;
24
+ };
25
+ /**
26
+ * Shares the farm has to release before the withdraw can burn its amount:
27
+ * the shortfall, and nothing more. Measured against captured builds: a
28
+ * request covered by the unstaked balance is built with no farms
29
+ * instructions at all, and anything above it unstakes exactly the
30
+ * difference.
31
+ */
32
+ export declare const kaminoUnstakeShares: ({ shares, unstakedShares }: KaminoWithdrawRequest) => KaminoShareAmount;
33
+ /** The operation a built transaction is supposed to perform. */
34
+ export type KaminoOperationIntent = {
35
+ deposit: KaminoTokenAmount;
36
+ } | {
37
+ withdraw: KaminoWithdrawRequest;
38
+ };
39
+ /**
40
+ * The priority fee the app injected: a compute unit limit and a price per
41
+ * unit. The fee the network charges is `limit × price`, paid in SOL by the
42
+ * fee payer, so both halves are a spend and both are checked against the
43
+ * values the app chose rather than accepted from the transaction.
44
+ */
45
+ export type KaminoPriorityFee = {
46
+ unitLimit: number;
47
+ unitPriceMicroLamports: bigint;
48
+ };
49
+ /** The request a built transaction is supposed to be the answer to. */
50
+ export type KaminoTransactionIntent = {
51
+ operation: KaminoOperationIntent;
52
+ vault: KaminoVaultInfo;
53
+ /**
54
+ * The user's Solana address: fee payer, sole signer, and the account every
55
+ * destination must belong to.
56
+ */
57
+ owner: string;
58
+ /**
59
+ * The priority fee the app injected, or `undefined` before injection — in
60
+ * which case any ComputeBudget instruction at all is a refusal, because
61
+ * Kamino's builder emits none and a fee we did not choose is SOL leaving
62
+ * the wallet.
63
+ */
64
+ priorityFee?: KaminoPriorityFee;
65
+ /**
66
+ * Whether the app has appended its attribution memo. `false` before
67
+ * injection, where a memo can only have come from the response — and the
68
+ * Memo program logs whatever it is handed, so a memo we did not write is
69
+ * text this app would be signing on somebody else's behalf.
70
+ */
71
+ carriesAttributionMemo: boolean;
72
+ };
73
+ /** The category a validation refusal falls into, for branching and tests. */
74
+ export type KaminoValidationFinding = 'vaultNotAllowed' | 'vaultDescriptorMismatch' | 'transactionShape' | 'unexpectedLookupTable' | 'accountResolution' | 'programNotAllowed' | 'unexpectedInstruction' | 'missingInstruction' | 'instructionNotForOperation' | 'malformedInstruction' | 'accountMismatch' | 'accountNotOwnedByUser' | 'amountMismatch' | 'amountOutOfRange' | 'unexpectedPriorityFee' | 'unexpectedMemo' | 'unattributableWritableAccount' | 'unreferencedWritableAccount' | 'derivationFailed';
75
+ /**
76
+ * A refusal from the fail-closed validator. Everything it finds is a refusal
77
+ * — nothing downgrades to a warning — and `finding` names the category so
78
+ * callers and tests branch on data rather than message text.
79
+ */
80
+ export declare class KaminoValidationError extends Error {
81
+ readonly finding: KaminoValidationFinding;
82
+ constructor(finding: KaminoValidationFinding, detail: string);
83
+ }
84
+ /**
85
+ * The user's associated token accounts for one mint, one per token program.
86
+ * Both token programs are tried because a mint belongs to exactly one and
87
+ * which one is not knowable from the address alone.
88
+ */
89
+ export declare const kaminoUserTokenAccounts: ({ owner, mint }: {
90
+ owner: string;
91
+ mint: string;
92
+ }) => Set<string>;
93
+ /**
94
+ * Fail-closed validation of a Kamino-built Solana transaction.
95
+ *
96
+ * Kamino builds the transaction and the app signs the bytes verbatim, so
97
+ * between an API response and a signature over it there is only this. It runs
98
+ * before simulation and before keysign, and every finding is a refusal.
99
+ *
100
+ * What it establishes, in layers: the shape (one unsigned signature, paid by
101
+ * the user, every lookup table the vault's own); the programs (every
102
+ * `programIdIndex` resolves to an allow-listed program — the outer bound on
103
+ * what the signature can authorise); the sequence (the instruction list
104
+ * matches the shape this operation produces, so a new instruction fails
105
+ * closed); the identity of every account that decides where money goes,
106
+ * compared against values the app already had — registry and local
107
+ * derivations, never the response, because checking a transaction the API
108
+ * built against metadata the same API supplied would be circular; the amounts
109
+ * (the kvault `u64` equals what the user was shown, the priority fee equals
110
+ * what the app injected); and the writable accounts (no unexplained writes).
111
+ *
112
+ * What it does not establish is what the `kvault` and `farms` programs do
113
+ * with the accounts they are handed. That is the protocol, and choosing to
114
+ * trust it is what the registry allow-list expresses.
115
+ *
116
+ * Pure — lookup tables arrive resolved, so tests can drive it against pinned
117
+ * contents. `validateKaminoTransactionOnline` is the fetching entry point.
118
+ */
119
+ export declare const validateKaminoTransaction: ({ transaction, intent, lookupTables, }: {
120
+ transaction: VersionedTransaction;
121
+ intent: KaminoTransactionIntent;
122
+ /** Table address to that table's full address list. */
123
+ lookupTables: Record<string, string[]>;
124
+ }) => void;
125
+ /**
126
+ * Resolves the transaction's address lookup tables from the RPC, then runs
127
+ * the pure validator against them.
128
+ *
129
+ * Rejects with `KaminoValidationError` for a refusal of the transaction, and
130
+ * with `KaminoWireError` when the lookup tables could not be resolved at all
131
+ * (missing table, stalled node past the read deadline, transport failure) —
132
+ * callers must not assume every rejection carries a `finding`.
133
+ */
134
+ export declare const validateKaminoTransactionOnline: ({ transaction, intent, }: {
135
+ transaction: VersionedTransaction;
136
+ intent: KaminoTransactionIntent;
137
+ }) => Promise<void>;
138
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/kamino/tx/validate.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAEjE,OAAO,EAAE,iBAAiB,EAAqB,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAGnF,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAiC3C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,sEAAsE;IACtE,MAAM,EAAE,iBAAiB,CAAA;IACzB;;;OAGG;IACH,cAAc,EAAE,iBAAiB,CAAA;CAClC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,4BAA4B,qBAAqB,KAAG,iBAGvF,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,qBAAqB,GAAG;IAAE,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAAG;IAAE,QAAQ,EAAE,qBAAqB,CAAA;CAAE,CAAA;AAExG;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,sBAAsB,EAAE,MAAM,CAAA;CAC/B,CAAA;AAED,uEAAuE;AACvE,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,qBAAqB,CAAA;IAChC,KAAK,EAAE,eAAe,CAAA;IACtB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B;;;;;OAKG;IACH,sBAAsB,EAAE,OAAO,CAAA;CAChC,CAAA;AAED,6EAA6E;AAC7E,MAAM,MAAM,uBAAuB,GAC/B,iBAAiB,GACjB,yBAAyB,GACzB,kBAAkB,GAClB,uBAAuB,GACvB,mBAAmB,GACnB,mBAAmB,GACnB,uBAAuB,GACvB,oBAAoB,GACpB,4BAA4B,GAC5B,sBAAsB,GACtB,iBAAiB,GACjB,uBAAuB,GACvB,gBAAgB,GAChB,kBAAkB,GAClB,uBAAuB,GACvB,gBAAgB,GAChB,+BAA+B,GAC/B,6BAA6B,GAC7B,kBAAkB,CAAA;AAEtB;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAA;gBAE7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM;CAK7D;AAMD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAAI,iBAAiB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,KAAG,GAAG,CAAC,MAAM,CAYpG,CAAA;AA0aD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,yBAAyB,GAAI,wCAIvC;IACD,WAAW,EAAE,oBAAoB,CAAA;IACjC,MAAM,EAAE,uBAAuB,CAAA;IAC/B,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CACvC,KAAG,IAkHH,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B,GAAU,0BAGnD;IACD,WAAW,EAAE,oBAAoB,CAAA;IACjC,MAAM,EAAE,uBAAuB,CAAA;CAChC,KAAG,OAAO,CAAC,IAAI,CAGf,CAAA"}