@haven-fi/solauto-sdk 1.0.685 → 1.0.687
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/dist/constants/solautoConstants.d.ts +1 -0
- package/dist/constants/solautoConstants.d.ts.map +1 -1
- package/dist/constants/solautoConstants.js +2 -1
- package/dist/services/transactions/index.d.ts +3 -2
- package/dist/services/transactions/index.d.ts.map +1 -1
- package/dist/services/transactions/index.js +2 -1
- package/dist/services/transactions/manager/clientTransactionsManager.d.ts +10 -0
- package/dist/services/transactions/manager/clientTransactionsManager.d.ts.map +1 -0
- package/dist/services/transactions/manager/clientTransactionsManager.js +75 -0
- package/dist/services/transactions/manager/index.d.ts +3 -0
- package/dist/services/transactions/manager/index.d.ts.map +1 -0
- package/dist/services/transactions/manager/index.js +18 -0
- package/dist/services/transactions/manager/transactionsManager.d.ts +64 -0
- package/dist/services/transactions/manager/transactionsManager.d.ts.map +1 -0
- package/dist/services/transactions/{transactionsManager.js → manager/transactionsManager.js} +21 -211
- package/dist/services/transactions/types/index.d.ts +4 -0
- package/dist/services/transactions/types/index.d.ts.map +1 -0
- package/dist/services/transactions/types/index.js +19 -0
- package/dist/services/transactions/types/lookupTables.d.ts +10 -0
- package/dist/services/transactions/types/lookupTables.d.ts.map +1 -0
- package/dist/services/transactions/types/lookupTables.js +25 -0
- package/dist/services/transactions/types/transactionItem.d.ts +16 -0
- package/dist/services/transactions/types/transactionItem.d.ts.map +1 -0
- package/dist/services/transactions/types/transactionItem.js +31 -0
- package/dist/services/transactions/types/transactionSet.d.ts +20 -0
- package/dist/services/transactions/types/transactionSet.d.ts.map +1 -0
- package/dist/services/transactions/types/transactionSet.js +79 -0
- package/dist/solautoPosition/positionUtils.js +1 -1
- package/dist/solautoPosition/solautoPositionEx.d.ts.map +1 -1
- package/dist/solautoPosition/solautoPositionEx.js +2 -1
- package/dist/utils/instructionUtils.d.ts.map +1 -1
- package/dist/utils/instructionUtils.js +3 -3
- package/dist/utils/switchboardUtils.d.ts +1 -0
- package/dist/utils/switchboardUtils.d.ts.map +1 -1
- package/dist/utils/switchboardUtils.js +10 -0
- package/local/txSandbox.ts +17 -23
- package/package.json +3 -1
- package/src/constants/solautoConstants.ts +2 -0
- package/src/services/transactions/index.ts +3 -2
- package/src/services/transactions/manager/clientTransactionsManager.ts +141 -0
- package/src/services/transactions/manager/index.ts +2 -0
- package/src/services/transactions/{transactionsManager.ts → manager/transactionsManager.ts} +46 -354
- package/src/services/transactions/types/index.ts +3 -0
- package/src/services/transactions/types/lookupTables.ts +37 -0
- package/src/services/transactions/types/transactionItem.ts +43 -0
- package/src/services/transactions/types/transactionSet.ts +114 -0
- package/src/solautoPosition/positionUtils.ts +1 -1
- package/src/solautoPosition/solautoPositionEx.ts +11 -12
- package/src/utils/instructionUtils.ts +6 -3
- package/src/utils/switchboardUtils.ts +17 -2
- package/tests/transactions/shared.ts +6 -3
- package/dist/services/transactions/transactionsManager.d.ts +0 -68
- package/dist/services/transactions/transactionsManager.d.ts.map +0 -1
@@ -1,41 +1,21 @@
|
|
1
1
|
import bs58 from "bs58";
|
2
|
-
import {
|
3
|
-
|
4
|
-
TransactionExpiredBlockheightExceededError,
|
5
|
-
} from "@solana/web3.js";
|
6
|
-
import {
|
7
|
-
AddressLookupTableInput,
|
8
|
-
transactionBuilder,
|
9
|
-
TransactionBuilder,
|
10
|
-
Umi,
|
11
|
-
} from "@metaplex-foundation/umi";
|
2
|
+
import { TransactionExpiredBlockheightExceededError } from "@solana/web3.js";
|
3
|
+
import { TransactionBuilder } from "@metaplex-foundation/umi";
|
12
4
|
import {
|
13
5
|
PriorityFeeSetting,
|
14
6
|
priorityFeeSettingValues,
|
15
|
-
TransactionItemInputs,
|
16
7
|
TransactionRunType,
|
17
|
-
} from "
|
18
|
-
import {
|
19
|
-
SOLAUTO_PROD_PROGRAM,
|
20
|
-
SOLAUTO_TEST_PROGRAM,
|
21
|
-
SWITCHBOARD_PRICE_FEED_IDS,
|
22
|
-
} from "../../constants";
|
8
|
+
} from "../../../types";
|
23
9
|
import {
|
24
10
|
consoleLog,
|
25
11
|
ErrorsToThrow,
|
26
12
|
retryWithExponentialBackoff,
|
27
|
-
addTxOptimizations,
|
28
|
-
getAddressLookupInputs,
|
29
13
|
sendSingleOptimizedTransaction,
|
30
|
-
buildSwbSubmitResponseTx,
|
31
|
-
getSwitchboardFeedData,
|
32
14
|
sendJitoBundledTransactions,
|
33
|
-
} from "
|
34
|
-
import {
|
35
|
-
import { getErrorInfo
|
36
|
-
|
37
|
-
const CHORES_TX_NAME = "account chores";
|
38
|
-
const MAX_SUPPORTED_ACCOUNT_LOCKS = 64;
|
15
|
+
} from "../../../utils";
|
16
|
+
import { TxHandler } from "../../solauto";
|
17
|
+
import { getErrorInfo } from "../transactionUtils";
|
18
|
+
import { LookupTables, TransactionItem, TransactionSet } from "../types";
|
39
19
|
|
40
20
|
export class TransactionTooLargeError extends Error {
|
41
21
|
constructor(message: string) {
|
@@ -45,183 +25,6 @@ export class TransactionTooLargeError extends Error {
|
|
45
25
|
}
|
46
26
|
}
|
47
27
|
|
48
|
-
class LookupTables {
|
49
|
-
cache: AddressLookupTableInput[] = [];
|
50
|
-
|
51
|
-
constructor(
|
52
|
-
public defaultLuts: string[],
|
53
|
-
private umi: Umi
|
54
|
-
) {}
|
55
|
-
|
56
|
-
async getLutInputs(
|
57
|
-
additionalAddresses?: string[]
|
58
|
-
): Promise<AddressLookupTableInput[]> {
|
59
|
-
const addresses = [...this.defaultLuts, ...(additionalAddresses ?? [])];
|
60
|
-
const currentCacheAddresses = this.cache.map((x) => x.publicKey.toString());
|
61
|
-
|
62
|
-
const missingAddresses = addresses.filter(
|
63
|
-
(x) => !currentCacheAddresses.includes(x)
|
64
|
-
);
|
65
|
-
if (missingAddresses) {
|
66
|
-
const additionalInputs = await getAddressLookupInputs(
|
67
|
-
this.umi,
|
68
|
-
missingAddresses
|
69
|
-
);
|
70
|
-
this.cache.push(...additionalInputs);
|
71
|
-
}
|
72
|
-
|
73
|
-
return this.cache;
|
74
|
-
}
|
75
|
-
|
76
|
-
reset() {
|
77
|
-
this.cache = this.cache.filter((x) =>
|
78
|
-
this.defaultLuts.includes(x.publicKey.toString())
|
79
|
-
);
|
80
|
-
}
|
81
|
-
}
|
82
|
-
|
83
|
-
export class TransactionItem {
|
84
|
-
lookupTableAddresses!: string[];
|
85
|
-
tx?: TransactionBuilder;
|
86
|
-
initialized: boolean = false;
|
87
|
-
orderPrio: number = 0;
|
88
|
-
|
89
|
-
constructor(
|
90
|
-
public fetchTx: (
|
91
|
-
attemptNum: number,
|
92
|
-
prevError?: Error
|
93
|
-
) => Promise<TransactionItemInputs | undefined>,
|
94
|
-
public name?: string
|
95
|
-
) {}
|
96
|
-
|
97
|
-
async initialize() {
|
98
|
-
await this.refetch(0);
|
99
|
-
this.initialized = true;
|
100
|
-
}
|
101
|
-
|
102
|
-
async refetch(attemptNum: number, prevError?: Error) {
|
103
|
-
const resp = await this.fetchTx(attemptNum, prevError);
|
104
|
-
this.tx = resp?.tx;
|
105
|
-
this.lookupTableAddresses = resp?.lookupTableAddresses ?? [];
|
106
|
-
this.orderPrio = resp?.orderPrio ?? 0;
|
107
|
-
}
|
108
|
-
|
109
|
-
uniqueAccounts(): string[] {
|
110
|
-
return Array.from(
|
111
|
-
new Set(
|
112
|
-
this.tx!.getInstructions()
|
113
|
-
.map((x) => [
|
114
|
-
x.programId.toString(),
|
115
|
-
...x.keys.map((y) => y.pubkey.toString()),
|
116
|
-
])
|
117
|
-
.flat()
|
118
|
-
)
|
119
|
-
);
|
120
|
-
}
|
121
|
-
}
|
122
|
-
|
123
|
-
class TransactionSet {
|
124
|
-
constructor(
|
125
|
-
private txHandler: TxHandler,
|
126
|
-
public lookupTables: LookupTables,
|
127
|
-
public items: TransactionItem[] = []
|
128
|
-
) {}
|
129
|
-
|
130
|
-
async lutInputs(): Promise<AddressLookupTableInput[]> {
|
131
|
-
const lutInputs = await this.lookupTables.getLutInputs(this.lutAddresses());
|
132
|
-
|
133
|
-
return lutInputs.filter(
|
134
|
-
(lut, index, self) =>
|
135
|
-
index ===
|
136
|
-
self.findIndex(
|
137
|
-
(item) => item.publicKey.toString() === lut.publicKey.toString()
|
138
|
-
)
|
139
|
-
);
|
140
|
-
}
|
141
|
-
|
142
|
-
async fitsWith(item: TransactionItem): Promise<boolean> {
|
143
|
-
if (!item.tx) {
|
144
|
-
return true;
|
145
|
-
}
|
146
|
-
|
147
|
-
const accountLocks = Array.from(
|
148
|
-
new Set([
|
149
|
-
...this.items.map((x) => x.uniqueAccounts()),
|
150
|
-
...item.uniqueAccounts(),
|
151
|
-
])
|
152
|
-
).length;
|
153
|
-
if (accountLocks > MAX_SUPPORTED_ACCOUNT_LOCKS) {
|
154
|
-
return false;
|
155
|
-
}
|
156
|
-
|
157
|
-
const singleTx = await this.getSingleTransaction();
|
158
|
-
const tx = addTxOptimizations(this.txHandler.umi, singleTx, 1, 1)
|
159
|
-
.add(item.tx)
|
160
|
-
.setAddressLookupTables(
|
161
|
-
await this.lookupTables.getLutInputs([
|
162
|
-
...this.lutAddresses(),
|
163
|
-
...item.lookupTableAddresses,
|
164
|
-
])
|
165
|
-
);
|
166
|
-
|
167
|
-
return tx.fitsInOneTransaction(this.txHandler.umi);
|
168
|
-
}
|
169
|
-
|
170
|
-
add(...items: TransactionItem[]) {
|
171
|
-
this.items.push(
|
172
|
-
...items.filter((x) => x.tx && x.tx.getInstructions().length > 0)
|
173
|
-
);
|
174
|
-
}
|
175
|
-
|
176
|
-
prepend(...items: TransactionItem[]) {
|
177
|
-
this.items.unshift(
|
178
|
-
...items.filter((x) => x.tx && x.tx.getInstructions().length > 0)
|
179
|
-
);
|
180
|
-
}
|
181
|
-
|
182
|
-
async reset() {
|
183
|
-
await this.txHandler.resetLiveTxUpdates();
|
184
|
-
}
|
185
|
-
|
186
|
-
async refetchAll(attemptNum: number, prevError?: Error) {
|
187
|
-
for (const item of this.items) {
|
188
|
-
await item.refetch(attemptNum, prevError);
|
189
|
-
}
|
190
|
-
}
|
191
|
-
|
192
|
-
async getSingleTransaction(): Promise<TransactionBuilder> {
|
193
|
-
const transactions = this.items
|
194
|
-
.filter((x) => x.tx && x.tx.getInstructions().length > 0)
|
195
|
-
.map((x) => x.tx!);
|
196
|
-
|
197
|
-
return transactionBuilder()
|
198
|
-
.add(transactions)
|
199
|
-
.setAddressLookupTables(await this.lutInputs());
|
200
|
-
}
|
201
|
-
|
202
|
-
lutAddresses(): string[] {
|
203
|
-
return Array.from(
|
204
|
-
new Set(this.items.map((x) => x.lookupTableAddresses).flat())
|
205
|
-
);
|
206
|
-
}
|
207
|
-
|
208
|
-
name(): string {
|
209
|
-
let names = this.items
|
210
|
-
.filter((x) => x.tx && Boolean(x.name))
|
211
|
-
.map((x) => x.name!.toLowerCase());
|
212
|
-
if (names.length > 1) {
|
213
|
-
names = names.filter((x) => x !== CHORES_TX_NAME);
|
214
|
-
}
|
215
|
-
if (names.length >= 3) {
|
216
|
-
return [names.slice(0, -1).join(", "), names[names.length - 1]].join(
|
217
|
-
", and "
|
218
|
-
);
|
219
|
-
} else {
|
220
|
-
return names.join(" & ");
|
221
|
-
}
|
222
|
-
}
|
223
|
-
}
|
224
|
-
|
225
28
|
export enum TransactionStatus {
|
226
29
|
Skipped = "Skipped",
|
227
30
|
Processing = "Processing",
|
@@ -245,33 +48,48 @@ interface RetryConfig {
|
|
245
48
|
retryDelay?: number;
|
246
49
|
}
|
247
50
|
|
248
|
-
export
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
51
|
+
export interface TransactionManagerArgs<T extends TxHandler> {
|
52
|
+
txHandler: T;
|
53
|
+
statusCallback?: (statuses: TransactionManagerStatuses) => void;
|
54
|
+
txRunType?: TransactionRunType;
|
55
|
+
priorityFeeSetting?: PriorityFeeSetting;
|
56
|
+
atomically?: boolean;
|
57
|
+
errorsToThrow?: ErrorsToThrow;
|
58
|
+
retryConfig?: RetryConfig;
|
59
|
+
}
|
60
|
+
|
61
|
+
export class TransactionsManager<T extends TxHandler> {
|
62
|
+
protected txHandler: T;
|
63
|
+
protected statusCallback?: (statuses: TransactionManagerStatuses) => void;
|
64
|
+
protected txRunType?: TransactionRunType;
|
65
|
+
protected priorityFeeSetting: PriorityFeeSetting;
|
66
|
+
protected atomically: boolean;
|
67
|
+
protected errorsToThrow?: ErrorsToThrow;
|
68
|
+
protected statuses: TransactionManagerStatuses = [];
|
69
|
+
protected lookupTables: LookupTables;
|
70
|
+
protected signableRetries: number;
|
71
|
+
protected totalRetries: number;
|
72
|
+
protected retryDelay: number;
|
254
73
|
|
255
74
|
updateOracleTxName = "update oracle";
|
256
75
|
|
257
|
-
constructor(
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
) {
|
76
|
+
constructor(args: TransactionManagerArgs<T>) {
|
77
|
+
this.txHandler = args.txHandler;
|
78
|
+
this.statusCallback = args.statusCallback;
|
79
|
+
this.txRunType = args.txRunType;
|
80
|
+
this.priorityFeeSetting = args.priorityFeeSetting ?? PriorityFeeSetting.Min;
|
81
|
+
this.atomically = args.atomically ?? true;
|
82
|
+
this.errorsToThrow = args.errorsToThrow;
|
83
|
+
|
266
84
|
this.lookupTables = new LookupTables(
|
267
85
|
this.txHandler.defaultLookupTables(),
|
268
86
|
this.txHandler.umi
|
269
87
|
);
|
270
88
|
this.signableRetries =
|
271
|
-
retryConfig?.signableRetries ?? retryConfig?.totalRetries ?? 4;
|
89
|
+
args.retryConfig?.signableRetries ?? args.retryConfig?.totalRetries ?? 4;
|
272
90
|
this.totalRetries =
|
273
|
-
retryConfig?.totalRetries ?? retryConfig?.signableRetries ?? 4;
|
274
|
-
this.retryDelay = retryConfig?.retryDelay ?? 150;
|
91
|
+
args.retryConfig?.totalRetries ?? args.retryConfig?.signableRetries ?? 4;
|
92
|
+
this.retryDelay = args.retryConfig?.retryDelay ?? 150;
|
275
93
|
}
|
276
94
|
|
277
95
|
private async assembleTransactionSets(
|
@@ -381,7 +199,7 @@ export class TransactionsManager {
|
|
381
199
|
}
|
382
200
|
}
|
383
201
|
|
384
|
-
|
202
|
+
protected getUpdatedPriorityFeeSetting(
|
385
203
|
prevError: Error | undefined,
|
386
204
|
attemptNum: number
|
387
205
|
) {
|
@@ -417,132 +235,6 @@ export class TransactionsManager {
|
|
417
235
|
});
|
418
236
|
}
|
419
237
|
|
420
|
-
private async updateLut(tx: TransactionBuilder, newLut: boolean) {
|
421
|
-
const lutInputs = await this.lookupTables.getLutInputs();
|
422
|
-
const updateLutTxName = `${newLut ? "create" : "update"} lookup table`;
|
423
|
-
await retryWithExponentialBackoff(
|
424
|
-
async (attemptNum, prevError) =>
|
425
|
-
await this.sendTransaction(
|
426
|
-
tx.setAddressLookupTables(lutInputs),
|
427
|
-
updateLutTxName,
|
428
|
-
attemptNum,
|
429
|
-
this.getUpdatedPriorityFeeSetting(prevError, attemptNum),
|
430
|
-
"skip-simulation"
|
431
|
-
),
|
432
|
-
this.signableRetries,
|
433
|
-
150,
|
434
|
-
this.errorsToThrow
|
435
|
-
);
|
436
|
-
await this.txHandler.refetchReferralState();
|
437
|
-
}
|
438
|
-
|
439
|
-
public async clientSend(
|
440
|
-
transactions: TransactionItem[]
|
441
|
-
): Promise<TransactionManagerStatuses> {
|
442
|
-
const items = [...transactions];
|
443
|
-
const client = this.txHandler as SolautoClient;
|
444
|
-
|
445
|
-
const updateLut = await client.updateLookupTable();
|
446
|
-
|
447
|
-
if (updateLut && (updateLut?.new || updateLut.accountsToAdd.length > 4)) {
|
448
|
-
await this.updateLut(updateLut.tx, updateLut.new);
|
449
|
-
}
|
450
|
-
this.lookupTables.defaultLuts = client.defaultLookupTables();
|
451
|
-
|
452
|
-
for (const item of items) {
|
453
|
-
await item.initialize();
|
454
|
-
}
|
455
|
-
|
456
|
-
const allAccounts = items.flatMap((item) => {
|
457
|
-
return (
|
458
|
-
item.tx
|
459
|
-
?.getInstructions()
|
460
|
-
.filter((ix) => {
|
461
|
-
return (
|
462
|
-
ix.programId.toString() === SOLAUTO_PROD_PROGRAM.toString() ||
|
463
|
-
ix.programId.toString() === SOLAUTO_TEST_PROGRAM.toString()
|
464
|
-
);
|
465
|
-
})
|
466
|
-
.flatMap((ix) => {
|
467
|
-
return ix.keys.map((key) => key.pubkey.toString());
|
468
|
-
}) ?? []
|
469
|
-
);
|
470
|
-
});
|
471
|
-
|
472
|
-
const swbOracle = allAccounts.find((x) =>
|
473
|
-
Object.values(SWITCHBOARD_PRICE_FEED_IDS)
|
474
|
-
.map((x) => x.feedId)
|
475
|
-
.includes(x ?? "")
|
476
|
-
);
|
477
|
-
if (swbOracle) {
|
478
|
-
const mint = new PublicKey(
|
479
|
-
Object.keys(SWITCHBOARD_PRICE_FEED_IDS).find(
|
480
|
-
(x) => SWITCHBOARD_PRICE_FEED_IDS[x].feedId === swbOracle
|
481
|
-
)!
|
482
|
-
);
|
483
|
-
const stale = (await getSwitchboardFeedData(client.connection, [mint]))[0]
|
484
|
-
.stale;
|
485
|
-
|
486
|
-
if (stale) {
|
487
|
-
this.txHandler.log("Requires oracle update...");
|
488
|
-
const swbTx = new TransactionItem(
|
489
|
-
async () =>
|
490
|
-
buildSwbSubmitResponseTx(client.connection, client.signer, mint),
|
491
|
-
this.updateOracleTxName
|
492
|
-
);
|
493
|
-
await swbTx.initialize();
|
494
|
-
items.unshift(swbTx);
|
495
|
-
}
|
496
|
-
}
|
497
|
-
|
498
|
-
let [choresBefore, choresAfter] = await getTransactionChores(
|
499
|
-
client,
|
500
|
-
transactionBuilder().add(
|
501
|
-
items
|
502
|
-
.filter((x) => x.tx && x.tx.getInstructions().length > 0)
|
503
|
-
.map((x) => x.tx!)
|
504
|
-
)
|
505
|
-
);
|
506
|
-
if (updateLut && !updateLut?.new) {
|
507
|
-
choresBefore = choresBefore.prepend(updateLut.tx);
|
508
|
-
}
|
509
|
-
if (choresBefore.getInstructions().length > 0) {
|
510
|
-
const chore = new TransactionItem(
|
511
|
-
async () => ({ tx: choresBefore }),
|
512
|
-
CHORES_TX_NAME
|
513
|
-
);
|
514
|
-
await chore.initialize();
|
515
|
-
items.unshift(chore);
|
516
|
-
this.txHandler.log(
|
517
|
-
"Chores before: ",
|
518
|
-
choresBefore.getInstructions().length
|
519
|
-
);
|
520
|
-
}
|
521
|
-
if (choresAfter.getInstructions().length > 0) {
|
522
|
-
const chore = new TransactionItem(
|
523
|
-
async () => ({ tx: choresAfter }),
|
524
|
-
CHORES_TX_NAME
|
525
|
-
);
|
526
|
-
await chore.initialize();
|
527
|
-
items.push(chore);
|
528
|
-
this.txHandler.log(
|
529
|
-
"Chores after: ",
|
530
|
-
choresAfter.getInstructions().length
|
531
|
-
);
|
532
|
-
}
|
533
|
-
|
534
|
-
const result = await this.send(items).catch((e) => {
|
535
|
-
client.resetLiveTxUpdates(false);
|
536
|
-
throw e;
|
537
|
-
});
|
538
|
-
|
539
|
-
if (this.txType !== "only-simulate") {
|
540
|
-
await client.resetLiveTxUpdates();
|
541
|
-
}
|
542
|
-
|
543
|
-
return result;
|
544
|
-
}
|
545
|
-
|
546
238
|
public async send(
|
547
239
|
items: TransactionItem[]
|
548
240
|
): Promise<TransactionManagerStatuses> {
|
@@ -641,7 +333,7 @@ export class TransactionsManager {
|
|
641
333
|
this.txHandler.signer,
|
642
334
|
this.txHandler.otherSigners,
|
643
335
|
transactions,
|
644
|
-
this.
|
336
|
+
this.txRunType,
|
645
337
|
this.getUpdatedPriorityFeeSetting(prevError, attemptNum),
|
646
338
|
() =>
|
647
339
|
this.updateStatusForSets(
|
@@ -658,7 +350,7 @@ export class TransactionsManager {
|
|
658
350
|
|
659
351
|
if (
|
660
352
|
error ||
|
661
|
-
(this.
|
353
|
+
(this.txRunType !== "only-simulate" &&
|
662
354
|
(!Boolean(txSigs) || txSigs?.length === 0))
|
663
355
|
) {
|
664
356
|
this.updateStatusForSets(
|
@@ -825,12 +517,12 @@ export class TransactionsManager {
|
|
825
517
|
return newItemSets;
|
826
518
|
}
|
827
519
|
|
828
|
-
|
520
|
+
protected async sendTransaction(
|
829
521
|
tx: TransactionBuilder,
|
830
522
|
txName: string,
|
831
523
|
attemptNum: number,
|
832
524
|
priorityFeeSetting?: PriorityFeeSetting,
|
833
|
-
|
525
|
+
txRunType?: TransactionRunType
|
834
526
|
) {
|
835
527
|
this.updateStatus(txName, TransactionStatus.Processing, attemptNum);
|
836
528
|
try {
|
@@ -838,7 +530,7 @@ export class TransactionsManager {
|
|
838
530
|
this.txHandler.umi,
|
839
531
|
this.txHandler.connection,
|
840
532
|
tx,
|
841
|
-
|
533
|
+
txRunType ?? this.txRunType,
|
842
534
|
priorityFeeSetting,
|
843
535
|
() =>
|
844
536
|
this.updateStatus(
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { AddressLookupTableInput, Umi } from "@metaplex-foundation/umi";
|
2
|
+
import { getAddressLookupInputs } from "../../../utils";
|
3
|
+
|
4
|
+
export class LookupTables {
|
5
|
+
cache: AddressLookupTableInput[] = [];
|
6
|
+
|
7
|
+
constructor(
|
8
|
+
public defaultLuts: string[],
|
9
|
+
private umi: Umi
|
10
|
+
) {}
|
11
|
+
|
12
|
+
async getLutInputs(
|
13
|
+
additionalAddresses?: string[]
|
14
|
+
): Promise<AddressLookupTableInput[]> {
|
15
|
+
const addresses = [...this.defaultLuts, ...(additionalAddresses ?? [])];
|
16
|
+
const currentCacheAddresses = this.cache.map((x) => x.publicKey.toString());
|
17
|
+
|
18
|
+
const missingAddresses = addresses.filter(
|
19
|
+
(x) => !currentCacheAddresses.includes(x)
|
20
|
+
);
|
21
|
+
if (missingAddresses) {
|
22
|
+
const additionalInputs = await getAddressLookupInputs(
|
23
|
+
this.umi,
|
24
|
+
missingAddresses
|
25
|
+
);
|
26
|
+
this.cache.push(...additionalInputs);
|
27
|
+
}
|
28
|
+
|
29
|
+
return this.cache;
|
30
|
+
}
|
31
|
+
|
32
|
+
reset() {
|
33
|
+
this.cache = this.cache.filter((x) =>
|
34
|
+
this.defaultLuts.includes(x.publicKey.toString())
|
35
|
+
);
|
36
|
+
}
|
37
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { TransactionBuilder } from "@metaplex-foundation/umi";
|
2
|
+
import { TransactionItemInputs } from "../../../types";
|
3
|
+
|
4
|
+
export class TransactionItem {
|
5
|
+
lookupTableAddresses!: string[];
|
6
|
+
tx?: TransactionBuilder;
|
7
|
+
initialized: boolean = false;
|
8
|
+
orderPrio: number = 0;
|
9
|
+
|
10
|
+
constructor(
|
11
|
+
public fetchTx: (
|
12
|
+
attemptNum: number,
|
13
|
+
prevError?: Error
|
14
|
+
) => Promise<TransactionItemInputs | undefined>,
|
15
|
+
public name?: string,
|
16
|
+
public oracleInteractor?: boolean
|
17
|
+
) {}
|
18
|
+
|
19
|
+
async initialize() {
|
20
|
+
await this.refetch(0);
|
21
|
+
this.initialized = true;
|
22
|
+
}
|
23
|
+
|
24
|
+
async refetch(attemptNum: number, prevError?: Error) {
|
25
|
+
const resp = await this.fetchTx(attemptNum, prevError);
|
26
|
+
this.tx = resp?.tx;
|
27
|
+
this.lookupTableAddresses = resp?.lookupTableAddresses ?? [];
|
28
|
+
this.orderPrio = resp?.orderPrio ?? 0;
|
29
|
+
}
|
30
|
+
|
31
|
+
uniqueAccounts(): string[] {
|
32
|
+
return Array.from(
|
33
|
+
new Set(
|
34
|
+
this.tx!.getInstructions()
|
35
|
+
.map((x) => [
|
36
|
+
x.programId.toString(),
|
37
|
+
...x.keys.map((y) => y.pubkey.toString()),
|
38
|
+
])
|
39
|
+
.flat()
|
40
|
+
)
|
41
|
+
);
|
42
|
+
}
|
43
|
+
}
|
@@ -0,0 +1,114 @@
|
|
1
|
+
import {
|
2
|
+
AddressLookupTableInput,
|
3
|
+
transactionBuilder,
|
4
|
+
TransactionBuilder,
|
5
|
+
} from "@metaplex-foundation/umi";
|
6
|
+
import { TxHandler } from "../../solauto";
|
7
|
+
import { LookupTables } from "./lookupTables";
|
8
|
+
import { TransactionItem } from "./transactionItem";
|
9
|
+
import { addTxOptimizations } from "../../../utils";
|
10
|
+
import { CHORES_TX_NAME } from "../../../constants";
|
11
|
+
|
12
|
+
const MAX_SUPPORTED_ACCOUNT_LOCKS = 64;
|
13
|
+
|
14
|
+
export class TransactionSet {
|
15
|
+
constructor(
|
16
|
+
private txHandler: TxHandler,
|
17
|
+
public lookupTables: LookupTables,
|
18
|
+
public items: TransactionItem[] = []
|
19
|
+
) {}
|
20
|
+
|
21
|
+
async lutInputs(): Promise<AddressLookupTableInput[]> {
|
22
|
+
const lutInputs = await this.lookupTables.getLutInputs(this.lutAddresses());
|
23
|
+
|
24
|
+
return lutInputs.filter(
|
25
|
+
(lut, index, self) =>
|
26
|
+
index ===
|
27
|
+
self.findIndex(
|
28
|
+
(item) => item.publicKey.toString() === lut.publicKey.toString()
|
29
|
+
)
|
30
|
+
);
|
31
|
+
}
|
32
|
+
|
33
|
+
async fitsWith(item: TransactionItem): Promise<boolean> {
|
34
|
+
if (!item.tx) {
|
35
|
+
return true;
|
36
|
+
}
|
37
|
+
|
38
|
+
const accountLocks = Array.from(
|
39
|
+
new Set([
|
40
|
+
...this.items.map((x) => x.uniqueAccounts()),
|
41
|
+
...item.uniqueAccounts(),
|
42
|
+
])
|
43
|
+
).length;
|
44
|
+
if (accountLocks > MAX_SUPPORTED_ACCOUNT_LOCKS) {
|
45
|
+
return false;
|
46
|
+
}
|
47
|
+
|
48
|
+
const singleTx = await this.getSingleTransaction();
|
49
|
+
const tx = addTxOptimizations(this.txHandler.umi, singleTx, 1, 1)
|
50
|
+
.add(item.tx)
|
51
|
+
.setAddressLookupTables(
|
52
|
+
await this.lookupTables.getLutInputs([
|
53
|
+
...this.lutAddresses(),
|
54
|
+
...item.lookupTableAddresses,
|
55
|
+
])
|
56
|
+
);
|
57
|
+
|
58
|
+
return tx.fitsInOneTransaction(this.txHandler.umi);
|
59
|
+
}
|
60
|
+
|
61
|
+
add(...items: TransactionItem[]) {
|
62
|
+
this.items.push(
|
63
|
+
...items.filter((x) => x.tx && x.tx.getInstructions().length > 0)
|
64
|
+
);
|
65
|
+
}
|
66
|
+
|
67
|
+
prepend(...items: TransactionItem[]) {
|
68
|
+
this.items.unshift(
|
69
|
+
...items.filter((x) => x.tx && x.tx.getInstructions().length > 0)
|
70
|
+
);
|
71
|
+
}
|
72
|
+
|
73
|
+
async reset() {
|
74
|
+
await this.txHandler.resetLiveTxUpdates();
|
75
|
+
}
|
76
|
+
|
77
|
+
async refetchAll(attemptNum: number, prevError?: Error) {
|
78
|
+
for (const item of this.items) {
|
79
|
+
await item.refetch(attemptNum, prevError);
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
async getSingleTransaction(): Promise<TransactionBuilder> {
|
84
|
+
const transactions = this.items
|
85
|
+
.filter((x) => x.tx && x.tx.getInstructions().length > 0)
|
86
|
+
.map((x) => x.tx!);
|
87
|
+
|
88
|
+
return transactionBuilder()
|
89
|
+
.add(transactions)
|
90
|
+
.setAddressLookupTables(await this.lutInputs());
|
91
|
+
}
|
92
|
+
|
93
|
+
lutAddresses(): string[] {
|
94
|
+
return Array.from(
|
95
|
+
new Set(this.items.map((x) => x.lookupTableAddresses).flat())
|
96
|
+
);
|
97
|
+
}
|
98
|
+
|
99
|
+
name(): string {
|
100
|
+
let names = this.items
|
101
|
+
.filter((x) => x.tx && Boolean(x.name))
|
102
|
+
.map((x) => x.name!.toLowerCase());
|
103
|
+
if (names.length > 1) {
|
104
|
+
names = names.filter((x) => x !== CHORES_TX_NAME);
|
105
|
+
}
|
106
|
+
if (names.length >= 3) {
|
107
|
+
return [names.slice(0, -1).join(", "), names[names.length - 1]].join(
|
108
|
+
", and "
|
109
|
+
);
|
110
|
+
} else {
|
111
|
+
return names.join(" & ");
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|