@vultisig/core-chain 2.36.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.
- package/CHANGELOG.md +29 -0
- package/dist/chains/cosmos/cosmosGasLimitRecord.d.ts.map +1 -1
- package/dist/chains/cosmos/cosmosGasLimitRecord.js +13 -14
- package/dist/chains/cosmos/cosmosGasLimitRecord.js.map +1 -1
- package/dist/chains/cosmos/gas.d.ts +16 -0
- package/dist/chains/cosmos/gas.d.ts.map +1 -1
- package/dist/chains/cosmos/gas.js +17 -1
- package/dist/chains/cosmos/gas.js.map +1 -1
- package/dist/chains/solana/kamino/KaminoServiceError.d.ts +63 -0
- package/dist/chains/solana/kamino/KaminoServiceError.d.ts.map +1 -0
- package/dist/chains/solana/kamino/KaminoServiceError.js +29 -0
- package/dist/chains/solana/kamino/KaminoServiceError.js.map +1 -0
- package/dist/chains/solana/kamino/amount.d.ts +141 -0
- package/dist/chains/solana/kamino/amount.d.ts.map +1 -0
- package/dist/chains/solana/kamino/amount.js +156 -0
- package/dist/chains/solana/kamino/amount.js.map +1 -0
- package/dist/chains/solana/kamino/api.d.ts +20 -0
- package/dist/chains/solana/kamino/api.d.ts.map +1 -0
- package/dist/chains/solana/kamino/api.js +59 -0
- package/dist/chains/solana/kamino/api.js.map +1 -0
- package/dist/chains/solana/kamino/baseUnits.d.ts +23 -0
- package/dist/chains/solana/kamino/baseUnits.d.ts.map +1 -0
- package/dist/chains/solana/kamino/baseUnits.js +30 -0
- package/dist/chains/solana/kamino/baseUnits.js.map +1 -0
- package/dist/chains/solana/kamino/config.d.ts +27 -0
- package/dist/chains/solana/kamino/config.d.ts.map +1 -0
- package/dist/chains/solana/kamino/config.js +27 -0
- package/dist/chains/solana/kamino/config.js.map +1 -0
- package/dist/chains/solana/kamino/decimal.d.ts +24 -0
- package/dist/chains/solana/kamino/decimal.d.ts.map +1 -0
- package/dist/chains/solana/kamino/decimal.js +52 -0
- package/dist/chains/solana/kamino/decimal.js.map +1 -0
- package/dist/chains/solana/kamino/models.d.ts +148 -0
- package/dist/chains/solana/kamino/models.d.ts.map +1 -0
- package/dist/chains/solana/kamino/models.js +2 -0
- package/dist/chains/solana/kamino/models.js.map +1 -0
- package/dist/chains/solana/kamino/position.d.ts +79 -0
- package/dist/chains/solana/kamino/position.d.ts.map +1 -0
- package/dist/chains/solana/kamino/position.js +52 -0
- package/dist/chains/solana/kamino/position.js.map +1 -0
- package/dist/chains/solana/kamino/rate.d.ts +57 -0
- package/dist/chains/solana/kamino/rate.d.ts.map +1 -0
- package/dist/chains/solana/kamino/rate.js +88 -0
- package/dist/chains/solana/kamino/rate.js.map +1 -0
- package/dist/chains/solana/kamino/registry.d.ts +70 -0
- package/dist/chains/solana/kamino/registry.d.ts.map +1 -0
- package/dist/chains/solana/kamino/registry.js +67 -0
- package/dist/chains/solana/kamino/registry.js.map +1 -0
- package/dist/chains/solana/kamino/tx/actions.d.ts +22 -0
- package/dist/chains/solana/kamino/tx/actions.d.ts.map +1 -0
- package/dist/chains/solana/kamino/tx/actions.js +85 -0
- package/dist/chains/solana/kamino/tx/actions.js.map +1 -0
- package/dist/chains/solana/kamino/tx/computeBudget.d.ts +66 -0
- package/dist/chains/solana/kamino/tx/computeBudget.d.ts.map +1 -0
- package/dist/chains/solana/kamino/tx/computeBudget.js +73 -0
- package/dist/chains/solana/kamino/tx/computeBudget.js.map +1 -0
- package/dist/chains/solana/kamino/tx/decode.d.ts +121 -0
- package/dist/chains/solana/kamino/tx/decode.d.ts.map +1 -0
- package/dist/chains/solana/kamino/tx/decode.js +458 -0
- package/dist/chains/solana/kamino/tx/decode.js.map +1 -0
- package/dist/chains/solana/kamino/tx/instructions.d.ts +260 -0
- package/dist/chains/solana/kamino/tx/instructions.d.ts.map +1 -0
- package/dist/chains/solana/kamino/tx/instructions.js +256 -0
- package/dist/chains/solana/kamino/tx/instructions.js.map +1 -0
- package/dist/chains/solana/kamino/tx/sequence.d.ts +123 -0
- package/dist/chains/solana/kamino/tx/sequence.d.ts.map +1 -0
- package/dist/chains/solana/kamino/tx/sequence.js +235 -0
- package/dist/chains/solana/kamino/tx/sequence.js.map +1 -0
- package/dist/chains/solana/kamino/tx/validate.d.ts +138 -0
- package/dist/chains/solana/kamino/tx/validate.d.ts.map +1 -0
- package/dist/chains/solana/kamino/tx/validate.js +542 -0
- package/dist/chains/solana/kamino/tx/validate.js.map +1 -0
- package/dist/chains/solana/kamino/tx/wire.d.ts +107 -0
- package/dist/chains/solana/kamino/tx/wire.d.ts.map +1 -0
- package/dist/chains/solana/kamino/tx/wire.js +274 -0
- package/dist/chains/solana/kamino/tx/wire.js.map +1 -0
- package/dist/chains/solana/kamino/vaultInfo.d.ts +17 -0
- package/dist/chains/solana/kamino/vaultInfo.d.ts.map +1 -0
- package/dist/chains/solana/kamino/vaultInfo.js +150 -0
- package/dist/chains/solana/kamino/vaultInfo.js.map +1 -0
- package/dist/chains/thorchain/ruji/services/fetchMergeableTokenBalances.d.ts +6 -1
- package/dist/chains/thorchain/ruji/services/fetchMergeableTokenBalances.d.ts.map +1 -1
- package/dist/chains/thorchain/ruji/services/fetchMergeableTokenBalances.js +6 -35
- package/dist/chains/thorchain/ruji/services/fetchMergeableTokenBalances.js.map +1 -1
- package/dist/swap/quote/findSwapQuote.d.ts +39 -0
- package/dist/swap/quote/findSwapQuote.d.ts.map +1 -1
- package/dist/swap/quote/findSwapQuote.js +33 -2
- package/dist/swap/quote/findSwapQuote.js.map +1 -1
- package/dist/tx/broadcast/cosmosSequenceMismatch.d.ts +26 -0
- package/dist/tx/broadcast/cosmosSequenceMismatch.d.ts.map +1 -0
- package/dist/tx/broadcast/cosmosSequenceMismatch.js +79 -0
- package/dist/tx/broadcast/cosmosSequenceMismatch.js.map +1 -0
- package/dist/tx/broadcast/resolvers/cosmos.d.ts +1 -0
- package/dist/tx/broadcast/resolvers/cosmos.d.ts.map +1 -1
- package/dist/tx/broadcast/resolvers/cosmos.js +7 -1
- package/dist/tx/broadcast/resolvers/cosmos.js.map +1 -1
- package/dist/tx/broadcast/transientRetry.d.ts.map +1 -1
- package/dist/tx/broadcast/transientRetry.js +6 -0
- package/dist/tx/broadcast/transientRetry.js.map +1 -1
- package/dist/utils/isValidTokenId.d.ts +6 -3
- package/dist/utils/isValidTokenId.d.ts.map +1 -1
- package/dist/utils/isValidTokenId.js +10 -3
- package/dist/utils/isValidTokenId.js.map +1 -1
- package/package.json +97 -2
|
@@ -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"}
|