torchsdk 1.0.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.
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Transaction builders
3
+ *
4
+ * Build unsigned transactions for buy, sell, create, vote, star, and message.
5
+ * Agents sign these locally and submit to the network.
6
+ */
7
+ import { Connection } from '@solana/web3.js';
8
+ import { BuyParams, SellParams, CreateTokenParams, VoteParams, StarParams, MessageParams, BorrowParams, RepayParams, LiquidateParams, TransactionResult, CreateTokenResult } from './types';
9
+ /**
10
+ * Build an unsigned buy transaction.
11
+ *
12
+ * @param connection - Solana RPC connection
13
+ * @param params - Buy parameters (mint, buyer, amount_sol in lamports, optional slippage_bps and vote)
14
+ * @returns Unsigned transaction and descriptive message
15
+ */
16
+ export declare const buildBuyTransaction: (connection: Connection, params: BuyParams) => Promise<TransactionResult>;
17
+ /**
18
+ * Build an unsigned sell transaction.
19
+ *
20
+ * @param connection - Solana RPC connection
21
+ * @param params - Sell parameters (mint, seller, amount_tokens in raw units, optional slippage_bps)
22
+ * @returns Unsigned transaction and descriptive message
23
+ */
24
+ export declare const buildSellTransaction: (connection: Connection, params: SellParams) => Promise<TransactionResult>;
25
+ /**
26
+ * Build an unsigned create token transaction.
27
+ *
28
+ * Returns the transaction (partially signed by the mint keypair) and the mint keypair
29
+ * so the agent can extract the mint address.
30
+ *
31
+ * @param connection - Solana RPC connection
32
+ * @param params - Create parameters (creator, name, symbol, metadata_uri)
33
+ * @returns Partially-signed transaction, mint PublicKey, and mint Keypair
34
+ */
35
+ export declare const buildCreateTokenTransaction: (connection: Connection, params: CreateTokenParams) => Promise<CreateTokenResult>;
36
+ /**
37
+ * Build an unsigned vote transaction.
38
+ *
39
+ * @param connection - Solana RPC connection
40
+ * @param params - Vote parameters (mint, voter, vote: "burn" | "return")
41
+ * @returns Unsigned transaction and descriptive message
42
+ */
43
+ export declare const buildVoteTransaction: (connection: Connection, params: VoteParams) => Promise<TransactionResult>;
44
+ /**
45
+ * Build an unsigned star transaction (costs 0.05 SOL).
46
+ *
47
+ * @param connection - Solana RPC connection
48
+ * @param params - Star parameters (mint, user)
49
+ * @returns Unsigned transaction and descriptive message
50
+ */
51
+ export declare const buildStarTransaction: (connection: Connection, params: StarParams) => Promise<TransactionResult>;
52
+ /**
53
+ * Build an unsigned message transaction (SPL Memo).
54
+ *
55
+ * @param connection - Solana RPC connection
56
+ * @param params - Message parameters (mint, sender, message text)
57
+ * @returns Unsigned transaction and descriptive message
58
+ */
59
+ export declare const buildMessageTransaction: (connection: Connection, params: MessageParams) => Promise<TransactionResult>;
60
+ /**
61
+ * Build an unsigned borrow transaction.
62
+ *
63
+ * Lock tokens as collateral in the collateral vault and receive SOL from treasury.
64
+ * Token must be migrated (has Raydium pool for price calculation).
65
+ *
66
+ * @param connection - Solana RPC connection
67
+ * @param params - Borrow parameters (mint, borrower, collateral_amount, sol_to_borrow)
68
+ * @returns Unsigned transaction and descriptive message
69
+ */
70
+ export declare const buildBorrowTransaction: (connection: Connection, params: BorrowParams) => Promise<TransactionResult>;
71
+ /**
72
+ * Build an unsigned repay transaction.
73
+ *
74
+ * Repay SOL debt. Interest is paid first, then principal.
75
+ * Full repay returns all collateral and closes the position.
76
+ *
77
+ * @param connection - Solana RPC connection
78
+ * @param params - Repay parameters (mint, borrower, sol_amount)
79
+ * @returns Unsigned transaction and descriptive message
80
+ */
81
+ export declare const buildRepayTransaction: (connection: Connection, params: RepayParams) => Promise<TransactionResult>;
82
+ /**
83
+ * Build an unsigned liquidate transaction.
84
+ *
85
+ * Permissionless — anyone can call when a borrower's LTV exceeds the
86
+ * liquidation threshold. Liquidator pays SOL and receives collateral + bonus.
87
+ *
88
+ * @param connection - Solana RPC connection
89
+ * @param params - Liquidate parameters (mint, liquidator, borrower)
90
+ * @returns Unsigned transaction and descriptive message
91
+ */
92
+ export declare const buildLiquidateTransaction: (connection: Connection, params: LiquidateParams) => Promise<TransactionResult>;
93
+ //# sourceMappingURL=transactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transactions.d.ts","sourceRoot":"","sources":["../src/transactions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,UAAU,EAOX,MAAM,iBAAiB,CAAA;AA2BxB,OAAO,EACL,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,UAAU,EACV,aAAa,EACb,YAAY,EACZ,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,SAAS,CAAA;AA8BhB;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,YAAY,UAAU,EACtB,QAAQ,SAAS,KAChB,OAAO,CAAC,iBAAiB,CAgG3B,CAAA;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,UAAU,EACtB,QAAQ,UAAU,KACjB,OAAO,CAAC,iBAAiB,CAoE3B,CAAA;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,GACtC,YAAY,UAAU,EACtB,QAAQ,iBAAiB,KACxB,OAAO,CAAC,iBAAiB,CAiE3B,CAAA;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,UAAU,EACtB,QAAQ,UAAU,KACjB,OAAO,CAAC,iBAAiB,CA4C3B,CAAA;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,UAAU,EACtB,QAAQ,UAAU,KACjB,OAAO,CAAC,iBAAiB,CAiD3B,CAAA;AAQD;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GAClC,YAAY,UAAU,EACtB,QAAQ,aAAa,KACpB,OAAO,CAAC,iBAAiB,CAiC3B,CAAA;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,GACjC,YAAY,UAAU,EACtB,QAAQ,YAAY,KACnB,OAAO,CAAC,iBAAiB,CAuD3B,CAAA;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GAChC,YAAY,UAAU,EACtB,QAAQ,WAAW,KAClB,OAAO,CAAC,iBAAiB,CA4C3B,CAAA;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GACpC,YAAY,UAAU,EACtB,QAAQ,eAAe,KACtB,OAAO,CAAC,iBAAiB,CAmE3B,CAAA"}
@@ -0,0 +1,550 @@
1
+ "use strict";
2
+ /**
3
+ * Transaction builders
4
+ *
5
+ * Build unsigned transactions for buy, sell, create, vote, star, and message.
6
+ * Agents sign these locally and submit to the network.
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.buildLiquidateTransaction = exports.buildRepayTransaction = exports.buildBorrowTransaction = exports.buildMessageTransaction = exports.buildStarTransaction = exports.buildVoteTransaction = exports.buildCreateTokenTransaction = exports.buildSellTransaction = exports.buildBuyTransaction = void 0;
13
+ const web3_js_1 = require("@solana/web3.js");
14
+ const spl_token_1 = require("@solana/spl-token");
15
+ const anchor_1 = require("@coral-xyz/anchor");
16
+ const program_1 = require("./program");
17
+ const constants_1 = require("./constants");
18
+ const tokens_1 = require("./tokens");
19
+ const torch_market_json_1 = __importDefault(require("./torch_market.json"));
20
+ // ============================================================================
21
+ // Helpers
22
+ // ============================================================================
23
+ const makeDummyProvider = (connection, payer) => {
24
+ const dummyWallet = {
25
+ publicKey: payer,
26
+ signTransaction: async (t) => t,
27
+ signAllTransactions: async (t) => t,
28
+ };
29
+ return new anchor_1.AnchorProvider(connection, dummyWallet, {});
30
+ };
31
+ const finalizeTransaction = async (connection, tx, feePayer) => {
32
+ const { blockhash } = await connection.getLatestBlockhash();
33
+ tx.recentBlockhash = blockhash;
34
+ tx.feePayer = feePayer;
35
+ };
36
+ // ============================================================================
37
+ // Buy
38
+ // ============================================================================
39
+ /**
40
+ * Build an unsigned buy transaction.
41
+ *
42
+ * @param connection - Solana RPC connection
43
+ * @param params - Buy parameters (mint, buyer, amount_sol in lamports, optional slippage_bps and vote)
44
+ * @returns Unsigned transaction and descriptive message
45
+ */
46
+ const buildBuyTransaction = async (connection, params) => {
47
+ const { mint: mintStr, buyer: buyerStr, amount_sol, slippage_bps = 100, vote } = params;
48
+ const mint = new web3_js_1.PublicKey(mintStr);
49
+ const buyer = new web3_js_1.PublicKey(buyerStr);
50
+ const tokenData = await (0, tokens_1.fetchTokenRaw)(connection, mint);
51
+ if (!tokenData)
52
+ throw new Error(`Token not found: ${mintStr}`);
53
+ const { bondingCurve } = tokenData;
54
+ if (bondingCurve.bonding_complete)
55
+ throw new Error('Bonding curve complete, trade on DEX');
56
+ // Calculate expected output
57
+ const virtualSol = BigInt(bondingCurve.virtual_sol_reserves.toString());
58
+ const virtualTokens = BigInt(bondingCurve.virtual_token_reserves.toString());
59
+ const realSol = BigInt(bondingCurve.real_sol_reserves.toString());
60
+ const solAmount = BigInt(amount_sol);
61
+ const result = (0, program_1.calculateTokensOut)(solAmount, virtualSol, virtualTokens, realSol);
62
+ // Apply slippage
63
+ const slippage = Math.max(10, Math.min(1000, slippage_bps));
64
+ const minTokens = (result.tokensToUser * BigInt(10000 - slippage)) / BigInt(10000);
65
+ // Derive PDAs
66
+ const [bondingCurvePda] = (0, program_1.getBondingCurvePda)(mint);
67
+ const [treasuryPda] = (0, program_1.getTokenTreasuryPda)(mint);
68
+ const [userPositionPda] = (0, program_1.getUserPositionPda)(bondingCurvePda, buyer);
69
+ const [userStatsPda] = (0, program_1.getUserStatsPda)(buyer);
70
+ const [globalConfigPda] = (0, program_1.getGlobalConfigPda)();
71
+ const [protocolTreasuryPda] = (0, program_1.getProtocolTreasuryPda)();
72
+ const bondingCurveTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, bondingCurvePda, true, spl_token_1.TOKEN_2022_PROGRAM_ID);
73
+ const treasuryTokenAccount = (0, program_1.getTreasuryTokenAccount)(mint, treasuryPda);
74
+ const userTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, buyer, false, spl_token_1.TOKEN_2022_PROGRAM_ID);
75
+ const tx = new web3_js_1.Transaction();
76
+ // Create user ATA if needed
77
+ tx.add((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(buyer, userTokenAccount, buyer, mint, spl_token_1.TOKEN_2022_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID));
78
+ const provider = makeDummyProvider(connection, buyer);
79
+ const program = new anchor_1.Program(torch_market_json_1.default, provider);
80
+ // Fetch global config for dev wallet
81
+ const globalConfigAccount = (await program.account.globalConfig.fetch(globalConfigPda));
82
+ const buyIx = await program.methods
83
+ .buy({
84
+ solAmount: new anchor_1.BN(amount_sol.toString()),
85
+ minTokensOut: new anchor_1.BN(minTokens.toString()),
86
+ vote: vote === 'return' ? true : vote === 'burn' ? false : null,
87
+ })
88
+ .accounts({
89
+ buyer,
90
+ globalConfig: globalConfigPda,
91
+ devWallet: globalConfigAccount.devWallet || globalConfigAccount.dev_wallet,
92
+ protocolTreasury: protocolTreasuryPda,
93
+ mint,
94
+ bondingCurve: bondingCurvePda,
95
+ tokenVault: bondingCurveTokenAccount,
96
+ treasury: treasuryPda,
97
+ treasuryTokenAccount,
98
+ userTokenAccount,
99
+ userPosition: userPositionPda,
100
+ userStats: userStatsPda,
101
+ tokenProgram: spl_token_1.TOKEN_2022_PROGRAM_ID,
102
+ associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
103
+ systemProgram: web3_js_1.SystemProgram.programId,
104
+ rent: web3_js_1.SYSVAR_RENT_PUBKEY,
105
+ })
106
+ .instruction();
107
+ tx.add(buyIx);
108
+ await finalizeTransaction(connection, tx, buyer);
109
+ return {
110
+ transaction: tx,
111
+ message: `Buy ${Number(result.tokensToUser) / 1e6} tokens for ${Number(solAmount) / 1e9} SOL`,
112
+ };
113
+ };
114
+ exports.buildBuyTransaction = buildBuyTransaction;
115
+ // ============================================================================
116
+ // Sell
117
+ // ============================================================================
118
+ /**
119
+ * Build an unsigned sell transaction.
120
+ *
121
+ * @param connection - Solana RPC connection
122
+ * @param params - Sell parameters (mint, seller, amount_tokens in raw units, optional slippage_bps)
123
+ * @returns Unsigned transaction and descriptive message
124
+ */
125
+ const buildSellTransaction = async (connection, params) => {
126
+ const { mint: mintStr, seller: sellerStr, amount_tokens, slippage_bps = 100 } = params;
127
+ const mint = new web3_js_1.PublicKey(mintStr);
128
+ const seller = new web3_js_1.PublicKey(sellerStr);
129
+ const tokenData = await (0, tokens_1.fetchTokenRaw)(connection, mint);
130
+ if (!tokenData)
131
+ throw new Error(`Token not found: ${mintStr}`);
132
+ const { bondingCurve } = tokenData;
133
+ if (bondingCurve.bonding_complete)
134
+ throw new Error('Bonding curve complete, trade on DEX');
135
+ // Calculate expected output
136
+ const virtualSol = BigInt(bondingCurve.virtual_sol_reserves.toString());
137
+ const virtualTokens = BigInt(bondingCurve.virtual_token_reserves.toString());
138
+ const tokenAmount = BigInt(amount_tokens);
139
+ const result = (0, program_1.calculateSolOut)(tokenAmount, virtualSol, virtualTokens);
140
+ // Apply slippage
141
+ const slippage = Math.max(10, Math.min(1000, slippage_bps));
142
+ const minSol = (result.solToUser * BigInt(10000 - slippage)) / BigInt(10000);
143
+ // Derive PDAs
144
+ const [bondingCurvePda] = (0, program_1.getBondingCurvePda)(mint);
145
+ const [treasuryPda] = (0, program_1.getTokenTreasuryPda)(mint);
146
+ const [userPositionPda] = (0, program_1.getUserPositionPda)(bondingCurvePda, seller);
147
+ const [userStatsPda] = (0, program_1.getUserStatsPda)(seller);
148
+ const [globalConfigPda] = (0, program_1.getGlobalConfigPda)();
149
+ const bondingCurveTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, bondingCurvePda, true, spl_token_1.TOKEN_2022_PROGRAM_ID);
150
+ const userTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, seller, false, spl_token_1.TOKEN_2022_PROGRAM_ID);
151
+ const tx = new web3_js_1.Transaction();
152
+ const provider = makeDummyProvider(connection, seller);
153
+ const program = new anchor_1.Program(torch_market_json_1.default, provider);
154
+ const sellIx = await program.methods
155
+ .sell({
156
+ tokenAmount: new anchor_1.BN(amount_tokens.toString()),
157
+ minSolOut: new anchor_1.BN(minSol.toString()),
158
+ })
159
+ .accounts({
160
+ seller,
161
+ mint,
162
+ bondingCurve: bondingCurvePda,
163
+ tokenVault: bondingCurveTokenAccount,
164
+ sellerTokenAccount: userTokenAccount,
165
+ userPosition: userPositionPda,
166
+ userStats: userStatsPda,
167
+ tokenProgram: spl_token_1.TOKEN_2022_PROGRAM_ID,
168
+ systemProgram: web3_js_1.SystemProgram.programId,
169
+ })
170
+ .instruction();
171
+ tx.add(sellIx);
172
+ await finalizeTransaction(connection, tx, seller);
173
+ return {
174
+ transaction: tx,
175
+ message: `Sell ${Number(tokenAmount) / 1e6} tokens for ${Number(result.solToUser) / 1e9} SOL`,
176
+ };
177
+ };
178
+ exports.buildSellTransaction = buildSellTransaction;
179
+ // ============================================================================
180
+ // Create Token
181
+ // ============================================================================
182
+ /**
183
+ * Build an unsigned create token transaction.
184
+ *
185
+ * Returns the transaction (partially signed by the mint keypair) and the mint keypair
186
+ * so the agent can extract the mint address.
187
+ *
188
+ * @param connection - Solana RPC connection
189
+ * @param params - Create parameters (creator, name, symbol, metadata_uri)
190
+ * @returns Partially-signed transaction, mint PublicKey, and mint Keypair
191
+ */
192
+ const buildCreateTokenTransaction = async (connection, params) => {
193
+ const { creator: creatorStr, name, symbol, metadata_uri } = params;
194
+ const creator = new web3_js_1.PublicKey(creatorStr);
195
+ if (name.length > 32)
196
+ throw new Error('Name must be 32 characters or less');
197
+ if (symbol.length > 10)
198
+ throw new Error('Symbol must be 10 characters or less');
199
+ // Grind for vanity "tm" suffix
200
+ let mint;
201
+ const maxAttempts = 500000;
202
+ let attempts = 0;
203
+ while (true) {
204
+ mint = web3_js_1.Keypair.generate();
205
+ attempts++;
206
+ if (mint.publicKey.toBase58().endsWith('tm'))
207
+ break;
208
+ if (attempts >= maxAttempts)
209
+ break;
210
+ }
211
+ // Derive PDAs
212
+ const [globalConfig] = (0, program_1.getGlobalConfigPda)();
213
+ const [bondingCurve] = (0, program_1.getBondingCurvePda)(mint.publicKey);
214
+ const [treasury] = (0, program_1.getTokenTreasuryPda)(mint.publicKey);
215
+ const bondingCurveTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(mint.publicKey, bondingCurve, true, spl_token_1.TOKEN_2022_PROGRAM_ID);
216
+ const treasuryTokenAccount = (0, program_1.getTreasuryTokenAccount)(mint.publicKey, treasury);
217
+ const tx = new web3_js_1.Transaction();
218
+ const provider = makeDummyProvider(connection, creator);
219
+ const program = new anchor_1.Program(torch_market_json_1.default, provider);
220
+ const createIx = await program.methods
221
+ .createToken({ name, symbol, uri: metadata_uri })
222
+ .accounts({
223
+ creator,
224
+ globalConfig,
225
+ mint: mint.publicKey,
226
+ bondingCurve,
227
+ tokenVault: bondingCurveTokenAccount,
228
+ treasury,
229
+ treasuryTokenAccount,
230
+ token2022Program: spl_token_1.TOKEN_2022_PROGRAM_ID,
231
+ associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
232
+ systemProgram: web3_js_1.SystemProgram.programId,
233
+ rent: web3_js_1.SYSVAR_RENT_PUBKEY,
234
+ })
235
+ .instruction();
236
+ tx.add(createIx);
237
+ await finalizeTransaction(connection, tx, creator);
238
+ // Partially sign with mint keypair
239
+ tx.partialSign(mint);
240
+ return {
241
+ transaction: tx,
242
+ mint: mint.publicKey,
243
+ mintKeypair: mint,
244
+ message: `Create token "${name}" ($${symbol})`,
245
+ };
246
+ };
247
+ exports.buildCreateTokenTransaction = buildCreateTokenTransaction;
248
+ // ============================================================================
249
+ // Vote
250
+ // ============================================================================
251
+ /**
252
+ * Build an unsigned vote transaction.
253
+ *
254
+ * @param connection - Solana RPC connection
255
+ * @param params - Vote parameters (mint, voter, vote: "burn" | "return")
256
+ * @returns Unsigned transaction and descriptive message
257
+ */
258
+ const buildVoteTransaction = async (connection, params) => {
259
+ const { mint: mintStr, voter: voterStr, vote } = params;
260
+ const mint = new web3_js_1.PublicKey(mintStr);
261
+ const voter = new web3_js_1.PublicKey(voterStr);
262
+ const tokenData = await (0, tokens_1.fetchTokenRaw)(connection, mint);
263
+ if (!tokenData)
264
+ throw new Error(`Token not found: ${mintStr}`);
265
+ const { bondingCurve } = tokenData;
266
+ if (!bondingCurve.bonding_complete)
267
+ throw new Error('Voting not open yet');
268
+ if (bondingCurve.vote_finalized)
269
+ throw new Error('Voting has ended');
270
+ // Derive PDAs
271
+ const [bondingCurvePda] = (0, program_1.getBondingCurvePda)(mint);
272
+ const [treasuryPda] = (0, program_1.getTokenTreasuryPda)(mint);
273
+ const [userPositionPda] = (0, program_1.getUserPositionPda)(bondingCurvePda, voter);
274
+ const [voteRecordPda] = (0, program_1.getVoteRecordPda)(bondingCurvePda, voter);
275
+ const tx = new web3_js_1.Transaction();
276
+ const provider = makeDummyProvider(connection, voter);
277
+ const program = new anchor_1.Program(torch_market_json_1.default, provider);
278
+ const voteIx = await program.methods
279
+ .vote(vote === 'return')
280
+ .accounts({
281
+ user: voter,
282
+ mint,
283
+ bondingCurve: bondingCurvePda,
284
+ treasury: treasuryPda,
285
+ userPosition: userPositionPda,
286
+ voteRecord: voteRecordPda,
287
+ systemProgram: web3_js_1.SystemProgram.programId,
288
+ })
289
+ .instruction();
290
+ tx.add(voteIx);
291
+ await finalizeTransaction(connection, tx, voter);
292
+ return {
293
+ transaction: tx,
294
+ message: `Vote to ${vote} treasury tokens`,
295
+ };
296
+ };
297
+ exports.buildVoteTransaction = buildVoteTransaction;
298
+ // ============================================================================
299
+ // Star
300
+ // ============================================================================
301
+ /**
302
+ * Build an unsigned star transaction (costs 0.05 SOL).
303
+ *
304
+ * @param connection - Solana RPC connection
305
+ * @param params - Star parameters (mint, user)
306
+ * @returns Unsigned transaction and descriptive message
307
+ */
308
+ const buildStarTransaction = async (connection, params) => {
309
+ const { mint: mintStr, user: userStr } = params;
310
+ const mint = new web3_js_1.PublicKey(mintStr);
311
+ const user = new web3_js_1.PublicKey(userStr);
312
+ const tokenData = await (0, tokens_1.fetchTokenRaw)(connection, mint);
313
+ if (!tokenData)
314
+ throw new Error(`Token not found: ${mintStr}`);
315
+ const { bondingCurve } = tokenData;
316
+ if (user.equals(bondingCurve.creator)) {
317
+ throw new Error('Cannot star your own token');
318
+ }
319
+ // Check if already starred
320
+ const [starRecordPda] = (0, program_1.getStarRecordPda)(user, mint);
321
+ const starRecord = await connection.getAccountInfo(starRecordPda);
322
+ if (starRecord)
323
+ throw new Error('Already starred this token');
324
+ // Derive PDAs
325
+ const [bondingCurvePda] = (0, program_1.getBondingCurvePda)(mint);
326
+ const [treasuryPda] = (0, program_1.getTokenTreasuryPda)(mint);
327
+ const tx = new web3_js_1.Transaction();
328
+ const provider = makeDummyProvider(connection, user);
329
+ const program = new anchor_1.Program(torch_market_json_1.default, provider);
330
+ const starIx = await program.methods
331
+ .starToken()
332
+ .accounts({
333
+ user,
334
+ mint,
335
+ bondingCurve: bondingCurvePda,
336
+ treasury: treasuryPda,
337
+ creator: bondingCurve.creator,
338
+ starRecord: starRecordPda,
339
+ systemProgram: web3_js_1.SystemProgram.programId,
340
+ })
341
+ .instruction();
342
+ tx.add(starIx);
343
+ await finalizeTransaction(connection, tx, user);
344
+ return {
345
+ transaction: tx,
346
+ message: 'Star token (costs 0.05 SOL)',
347
+ };
348
+ };
349
+ exports.buildStarTransaction = buildStarTransaction;
350
+ // ============================================================================
351
+ // Message
352
+ // ============================================================================
353
+ const MAX_MESSAGE_LENGTH = 500;
354
+ /**
355
+ * Build an unsigned message transaction (SPL Memo).
356
+ *
357
+ * @param connection - Solana RPC connection
358
+ * @param params - Message parameters (mint, sender, message text)
359
+ * @returns Unsigned transaction and descriptive message
360
+ */
361
+ const buildMessageTransaction = async (connection, params) => {
362
+ const { mint: mintStr, sender: senderStr, message } = params;
363
+ if (message.length > MAX_MESSAGE_LENGTH) {
364
+ throw new Error(`Message must be ${MAX_MESSAGE_LENGTH} characters or less`);
365
+ }
366
+ if (message.trim().length === 0) {
367
+ throw new Error('Message cannot be empty');
368
+ }
369
+ const mint = new web3_js_1.PublicKey(mintStr);
370
+ const sender = new web3_js_1.PublicKey(senderStr);
371
+ const tokenData = await (0, tokens_1.fetchTokenRaw)(connection, mint);
372
+ if (!tokenData)
373
+ throw new Error(`Token not found: ${mintStr}`);
374
+ const tx = new web3_js_1.Transaction();
375
+ // Prefix memo with mint address for indexing
376
+ const prefixedMessage = `[${mintStr}] ${message}`;
377
+ const memoIx = new web3_js_1.TransactionInstruction({
378
+ programId: constants_1.MEMO_PROGRAM_ID,
379
+ keys: [{ pubkey: sender, isSigner: true, isWritable: false }],
380
+ data: Buffer.from(prefixedMessage, 'utf-8'),
381
+ });
382
+ tx.add(memoIx);
383
+ await finalizeTransaction(connection, tx, sender);
384
+ return {
385
+ transaction: tx,
386
+ message: `Post message on token page`,
387
+ };
388
+ };
389
+ exports.buildMessageTransaction = buildMessageTransaction;
390
+ // ============================================================================
391
+ // Borrow (V2.4)
392
+ // ============================================================================
393
+ /**
394
+ * Build an unsigned borrow transaction.
395
+ *
396
+ * Lock tokens as collateral in the collateral vault and receive SOL from treasury.
397
+ * Token must be migrated (has Raydium pool for price calculation).
398
+ *
399
+ * @param connection - Solana RPC connection
400
+ * @param params - Borrow parameters (mint, borrower, collateral_amount, sol_to_borrow)
401
+ * @returns Unsigned transaction and descriptive message
402
+ */
403
+ const buildBorrowTransaction = async (connection, params) => {
404
+ const { mint: mintStr, borrower: borrowerStr, collateral_amount, sol_to_borrow } = params;
405
+ const mint = new web3_js_1.PublicKey(mintStr);
406
+ const borrower = new web3_js_1.PublicKey(borrowerStr);
407
+ // Derive PDAs
408
+ const [bondingCurvePda] = (0, program_1.getBondingCurvePda)(mint);
409
+ const [treasuryPda] = (0, program_1.getTokenTreasuryPda)(mint);
410
+ const [collateralVaultPda] = (0, program_1.getCollateralVaultPda)(mint);
411
+ const [loanPositionPda] = (0, program_1.getLoanPositionPda)(mint, borrower);
412
+ const borrowerTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, borrower, false, spl_token_1.TOKEN_2022_PROGRAM_ID);
413
+ // Get Raydium pool accounts for price calculation
414
+ const raydium = (0, program_1.getRaydiumMigrationAccounts)(mint);
415
+ const tx = new web3_js_1.Transaction();
416
+ const provider = makeDummyProvider(connection, borrower);
417
+ const program = new anchor_1.Program(torch_market_json_1.default, provider);
418
+ const borrowIx = await program.methods
419
+ .borrow({
420
+ collateralAmount: new anchor_1.BN(collateral_amount.toString()),
421
+ solToBorrow: new anchor_1.BN(sol_to_borrow.toString()),
422
+ })
423
+ .accounts({
424
+ borrower,
425
+ mint,
426
+ bondingCurve: bondingCurvePda,
427
+ treasury: treasuryPda,
428
+ collateralVault: collateralVaultPda,
429
+ borrowerTokenAccount,
430
+ loanPosition: loanPositionPda,
431
+ poolState: raydium.poolState,
432
+ tokenVault0: raydium.token0Vault,
433
+ tokenVault1: raydium.token1Vault,
434
+ tokenProgram: spl_token_1.TOKEN_2022_PROGRAM_ID,
435
+ systemProgram: web3_js_1.SystemProgram.programId,
436
+ })
437
+ .instruction();
438
+ tx.add(borrowIx);
439
+ await finalizeTransaction(connection, tx, borrower);
440
+ return {
441
+ transaction: tx,
442
+ message: `Borrow ${Number(sol_to_borrow) / 1e9} SOL with ${Number(collateral_amount) / 1e6} tokens as collateral`,
443
+ };
444
+ };
445
+ exports.buildBorrowTransaction = buildBorrowTransaction;
446
+ // ============================================================================
447
+ // Repay (V2.4)
448
+ // ============================================================================
449
+ /**
450
+ * Build an unsigned repay transaction.
451
+ *
452
+ * Repay SOL debt. Interest is paid first, then principal.
453
+ * Full repay returns all collateral and closes the position.
454
+ *
455
+ * @param connection - Solana RPC connection
456
+ * @param params - Repay parameters (mint, borrower, sol_amount)
457
+ * @returns Unsigned transaction and descriptive message
458
+ */
459
+ const buildRepayTransaction = async (connection, params) => {
460
+ const { mint: mintStr, borrower: borrowerStr, sol_amount } = params;
461
+ const mint = new web3_js_1.PublicKey(mintStr);
462
+ const borrower = new web3_js_1.PublicKey(borrowerStr);
463
+ // Derive PDAs
464
+ const [treasuryPda] = (0, program_1.getTokenTreasuryPda)(mint);
465
+ const [collateralVaultPda] = (0, program_1.getCollateralVaultPda)(mint);
466
+ const [loanPositionPda] = (0, program_1.getLoanPositionPda)(mint, borrower);
467
+ const borrowerTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, borrower, false, spl_token_1.TOKEN_2022_PROGRAM_ID);
468
+ const tx = new web3_js_1.Transaction();
469
+ const provider = makeDummyProvider(connection, borrower);
470
+ const program = new anchor_1.Program(torch_market_json_1.default, provider);
471
+ const repayIx = await program.methods
472
+ .repay(new anchor_1.BN(sol_amount.toString()))
473
+ .accounts({
474
+ borrower,
475
+ mint,
476
+ treasury: treasuryPda,
477
+ collateralVault: collateralVaultPda,
478
+ borrowerTokenAccount,
479
+ loanPosition: loanPositionPda,
480
+ tokenProgram: spl_token_1.TOKEN_2022_PROGRAM_ID,
481
+ systemProgram: web3_js_1.SystemProgram.programId,
482
+ })
483
+ .instruction();
484
+ tx.add(repayIx);
485
+ await finalizeTransaction(connection, tx, borrower);
486
+ return {
487
+ transaction: tx,
488
+ message: `Repay ${Number(sol_amount) / 1e9} SOL`,
489
+ };
490
+ };
491
+ exports.buildRepayTransaction = buildRepayTransaction;
492
+ // ============================================================================
493
+ // Liquidate (V2.4)
494
+ // ============================================================================
495
+ /**
496
+ * Build an unsigned liquidate transaction.
497
+ *
498
+ * Permissionless — anyone can call when a borrower's LTV exceeds the
499
+ * liquidation threshold. Liquidator pays SOL and receives collateral + bonus.
500
+ *
501
+ * @param connection - Solana RPC connection
502
+ * @param params - Liquidate parameters (mint, liquidator, borrower)
503
+ * @returns Unsigned transaction and descriptive message
504
+ */
505
+ const buildLiquidateTransaction = async (connection, params) => {
506
+ const { mint: mintStr, liquidator: liquidatorStr, borrower: borrowerStr } = params;
507
+ const mint = new web3_js_1.PublicKey(mintStr);
508
+ const liquidator = new web3_js_1.PublicKey(liquidatorStr);
509
+ const borrower = new web3_js_1.PublicKey(borrowerStr);
510
+ // Derive PDAs
511
+ const [bondingCurvePda] = (0, program_1.getBondingCurvePda)(mint);
512
+ const [treasuryPda] = (0, program_1.getTokenTreasuryPda)(mint);
513
+ const [collateralVaultPda] = (0, program_1.getCollateralVaultPda)(mint);
514
+ const [loanPositionPda] = (0, program_1.getLoanPositionPda)(mint, borrower);
515
+ const liquidatorTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, liquidator, false, spl_token_1.TOKEN_2022_PROGRAM_ID);
516
+ // Get Raydium pool accounts for price calculation
517
+ const raydium = (0, program_1.getRaydiumMigrationAccounts)(mint);
518
+ const tx = new web3_js_1.Transaction();
519
+ // Create liquidator ATA if needed
520
+ tx.add((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(liquidator, liquidatorTokenAccount, liquidator, mint, spl_token_1.TOKEN_2022_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID));
521
+ const provider = makeDummyProvider(connection, liquidator);
522
+ const program = new anchor_1.Program(torch_market_json_1.default, provider);
523
+ const liquidateIx = await program.methods
524
+ .liquidate()
525
+ .accounts({
526
+ liquidator,
527
+ borrower,
528
+ mint,
529
+ bondingCurve: bondingCurvePda,
530
+ treasury: treasuryPda,
531
+ collateralVault: collateralVaultPda,
532
+ liquidatorTokenAccount,
533
+ loanPosition: loanPositionPda,
534
+ poolState: raydium.poolState,
535
+ tokenVault0: raydium.token0Vault,
536
+ tokenVault1: raydium.token1Vault,
537
+ tokenProgram: spl_token_1.TOKEN_2022_PROGRAM_ID,
538
+ associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
539
+ systemProgram: web3_js_1.SystemProgram.programId,
540
+ })
541
+ .instruction();
542
+ tx.add(liquidateIx);
543
+ await finalizeTransaction(connection, tx, liquidator);
544
+ return {
545
+ transaction: tx,
546
+ message: `Liquidate loan position for ${borrowerStr}`,
547
+ };
548
+ };
549
+ exports.buildLiquidateTransaction = buildLiquidateTransaction;
550
+ //# sourceMappingURL=transactions.js.map