@loyal-labs/transactions 0.1.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/dist/index.js ADDED
@@ -0,0 +1,521 @@
1
+ // src/LoyalTransactionsClient.ts
2
+ import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";
3
+
4
+ // src/idl.ts
5
+ var IDL = {
6
+ address: "4ewpzEPF5xrVAHeRkoe7XS1yKFGQBekD7PgFwEz9SaxY",
7
+ metadata: {
8
+ name: "telegramTransfer",
9
+ version: "0.1.0",
10
+ spec: "0.1.0",
11
+ description: "Created with Anchor"
12
+ },
13
+ instructions: [
14
+ {
15
+ name: "claimDeposit",
16
+ discriminator: [201, 106, 1, 224, 122, 144, 210, 155],
17
+ accounts: [
18
+ {
19
+ name: "recipient",
20
+ docs: ["can be a new address"],
21
+ writable: true
22
+ },
23
+ {
24
+ name: "vault",
25
+ writable: true,
26
+ pda: {
27
+ seeds: [
28
+ {
29
+ kind: "const",
30
+ value: [118, 97, 117, 108, 116]
31
+ }
32
+ ]
33
+ }
34
+ },
35
+ {
36
+ name: "deposit",
37
+ writable: true,
38
+ pda: {
39
+ seeds: [
40
+ {
41
+ kind: "const",
42
+ value: [100, 101, 112, 111, 115, 105, 116]
43
+ },
44
+ {
45
+ kind: "account",
46
+ path: "deposit.user",
47
+ account: "deposit"
48
+ },
49
+ {
50
+ kind: "account",
51
+ path: "deposit.username",
52
+ account: "deposit"
53
+ }
54
+ ]
55
+ }
56
+ },
57
+ {
58
+ name: "session"
59
+ },
60
+ {
61
+ name: "systemProgram",
62
+ address: "11111111111111111111111111111111"
63
+ }
64
+ ],
65
+ args: [
66
+ {
67
+ name: "amount",
68
+ type: "u64"
69
+ }
70
+ ]
71
+ },
72
+ {
73
+ name: "depositForUsername",
74
+ discriminator: [85, 11, 120, 21, 51, 229, 125, 220],
75
+ accounts: [
76
+ {
77
+ name: "payer",
78
+ writable: true,
79
+ signer: true
80
+ },
81
+ {
82
+ name: "depositor",
83
+ writable: true,
84
+ signer: true
85
+ },
86
+ {
87
+ name: "vault",
88
+ writable: true,
89
+ pda: {
90
+ seeds: [
91
+ {
92
+ kind: "const",
93
+ value: [118, 97, 117, 108, 116]
94
+ }
95
+ ]
96
+ }
97
+ },
98
+ {
99
+ name: "deposit",
100
+ writable: true,
101
+ pda: {
102
+ seeds: [
103
+ {
104
+ kind: "const",
105
+ value: [100, 101, 112, 111, 115, 105, 116]
106
+ },
107
+ {
108
+ kind: "account",
109
+ path: "depositor"
110
+ },
111
+ {
112
+ kind: "arg",
113
+ path: "username"
114
+ }
115
+ ]
116
+ }
117
+ },
118
+ {
119
+ name: "systemProgram",
120
+ address: "11111111111111111111111111111111"
121
+ }
122
+ ],
123
+ args: [
124
+ {
125
+ name: "username",
126
+ type: "string"
127
+ },
128
+ {
129
+ name: "amount",
130
+ type: "u64"
131
+ }
132
+ ]
133
+ },
134
+ {
135
+ name: "refundDeposit",
136
+ discriminator: [19, 19, 78, 50, 187, 10, 162, 229],
137
+ accounts: [
138
+ {
139
+ name: "depositor",
140
+ writable: true,
141
+ signer: true
142
+ },
143
+ {
144
+ name: "vault",
145
+ writable: true,
146
+ pda: {
147
+ seeds: [
148
+ {
149
+ kind: "const",
150
+ value: [118, 97, 117, 108, 116]
151
+ }
152
+ ]
153
+ }
154
+ },
155
+ {
156
+ name: "deposit",
157
+ writable: true,
158
+ pda: {
159
+ seeds: [
160
+ {
161
+ kind: "const",
162
+ value: [100, 101, 112, 111, 115, 105, 116]
163
+ },
164
+ {
165
+ kind: "account",
166
+ path: "depositor"
167
+ },
168
+ {
169
+ kind: "account",
170
+ path: "deposit.username",
171
+ account: "deposit"
172
+ }
173
+ ]
174
+ }
175
+ }
176
+ ],
177
+ args: [
178
+ {
179
+ name: "amount",
180
+ type: "u64"
181
+ }
182
+ ]
183
+ }
184
+ ],
185
+ accounts: [
186
+ {
187
+ name: "deposit",
188
+ discriminator: [148, 146, 121, 66, 207, 173, 21, 227]
189
+ },
190
+ {
191
+ name: "telegramSession",
192
+ discriminator: [166, 166, 101, 241, 97, 253, 72, 138]
193
+ },
194
+ {
195
+ name: "vault",
196
+ discriminator: [211, 8, 232, 43, 2, 152, 117, 119]
197
+ }
198
+ ],
199
+ errors: [
200
+ {
201
+ code: 6000,
202
+ name: "overflow",
203
+ msg: "overflow"
204
+ },
205
+ {
206
+ code: 6001,
207
+ name: "insufficientVault",
208
+ msg: "Insufficient Vault"
209
+ },
210
+ {
211
+ code: 6002,
212
+ name: "insufficientDeposit",
213
+ msg: "Insufficient Deposit"
214
+ },
215
+ {
216
+ code: 6003,
217
+ name: "notVerified",
218
+ msg: "Not Verified"
219
+ },
220
+ {
221
+ code: 6004,
222
+ name: "expiredSignature",
223
+ msg: "Expired Signature"
224
+ },
225
+ {
226
+ code: 6005,
227
+ name: "replay",
228
+ msg: "replay"
229
+ },
230
+ {
231
+ code: 6006,
232
+ name: "invalidEd25519",
233
+ msg: "Invalid Ed25519"
234
+ },
235
+ {
236
+ code: 6007,
237
+ name: "invalidUsername",
238
+ msg: "Invalid Username"
239
+ },
240
+ {
241
+ code: 6008,
242
+ name: "invalidRecipient",
243
+ msg: "Invalid Recipient"
244
+ },
245
+ {
246
+ code: 6009,
247
+ name: "invalidDepositor",
248
+ msg: "Invalid Depositor"
249
+ }
250
+ ],
251
+ types: [
252
+ {
253
+ name: "deposit",
254
+ docs: ["A deposit account for a user and token mint."],
255
+ type: {
256
+ kind: "struct",
257
+ fields: [
258
+ {
259
+ name: "user",
260
+ type: "pubkey"
261
+ },
262
+ {
263
+ name: "username",
264
+ type: "string"
265
+ },
266
+ {
267
+ name: "amount",
268
+ type: "u64"
269
+ },
270
+ {
271
+ name: "lastNonce",
272
+ type: "u64"
273
+ }
274
+ ]
275
+ }
276
+ },
277
+ {
278
+ name: "telegramSession",
279
+ type: {
280
+ kind: "struct",
281
+ fields: [
282
+ {
283
+ name: "userWallet",
284
+ type: "pubkey"
285
+ },
286
+ {
287
+ name: "username",
288
+ type: "string"
289
+ },
290
+ {
291
+ name: "validationBytes",
292
+ type: "bytes"
293
+ },
294
+ {
295
+ name: "verified",
296
+ type: "bool"
297
+ },
298
+ {
299
+ name: "authAt",
300
+ type: "u64"
301
+ },
302
+ {
303
+ name: "verifiedAt",
304
+ type: {
305
+ option: "u64"
306
+ }
307
+ }
308
+ ]
309
+ }
310
+ },
311
+ {
312
+ name: "vault",
313
+ docs: ["A vault storing deposited SOL."],
314
+ type: {
315
+ kind: "struct",
316
+ fields: [
317
+ {
318
+ name: "bump",
319
+ type: "u8"
320
+ },
321
+ {
322
+ name: "totalDeposited",
323
+ type: "u64"
324
+ }
325
+ ]
326
+ }
327
+ }
328
+ ]
329
+ };
330
+
331
+ // src/constants.ts
332
+ import { PublicKey } from "@solana/web3.js";
333
+ var PROGRAM_ID = new PublicKey("4ewpzEPF5xrVAHeRkoe7XS1yKFGQBekD7PgFwEz9SaxY");
334
+ var DEPOSIT_SEED = "deposit";
335
+ var DEPOSIT_SEED_BYTES = Buffer.from(DEPOSIT_SEED);
336
+ var VAULT_SEED = "vault";
337
+ var VAULT_SEED_BYTES = Buffer.from(VAULT_SEED);
338
+ var LAMPORTS_PER_SOL = 1e9;
339
+ function solToLamports(sol) {
340
+ return Math.floor(sol * LAMPORTS_PER_SOL);
341
+ }
342
+ function lamportsToSol(lamports) {
343
+ return lamports / LAMPORTS_PER_SOL;
344
+ }
345
+
346
+ // src/pda.ts
347
+ import { PublicKey as PublicKey2 } from "@solana/web3.js";
348
+ function findDepositPda(depositor, username, programId = PROGRAM_ID) {
349
+ return PublicKey2.findProgramAddressSync([DEPOSIT_SEED_BYTES, depositor.toBuffer(), Buffer.from(username)], programId);
350
+ }
351
+ function findVaultPda(programId = PROGRAM_ID) {
352
+ return PublicKey2.findProgramAddressSync([VAULT_SEED_BYTES], programId);
353
+ }
354
+
355
+ // src/wallet-adapter.ts
356
+ import {
357
+ VersionedTransaction
358
+ } from "@solana/web3.js";
359
+
360
+ // src/types.ts
361
+ function isKeypair(signer) {
362
+ return "secretKey" in signer && signer.secretKey instanceof Uint8Array;
363
+ }
364
+ function isAnchorProvider(signer) {
365
+ return "wallet" in signer && "connection" in signer && "opts" in signer;
366
+ }
367
+ function isWalletLike(signer) {
368
+ return "publicKey" in signer && "signTransaction" in signer && "signAllTransactions" in signer && !isKeypair(signer) && !isAnchorProvider(signer);
369
+ }
370
+
371
+ // src/wallet-adapter.ts
372
+ class InternalWalletAdapter {
373
+ signer;
374
+ publicKey;
375
+ constructor(signer, publicKey) {
376
+ this.signer = signer;
377
+ this.publicKey = publicKey;
378
+ }
379
+ static from(signer) {
380
+ const publicKey = InternalWalletAdapter.getPublicKey(signer);
381
+ return new InternalWalletAdapter(signer, publicKey);
382
+ }
383
+ static getPublicKey(signer) {
384
+ if (isKeypair(signer)) {
385
+ return signer.publicKey;
386
+ }
387
+ if (isAnchorProvider(signer)) {
388
+ return signer.wallet.publicKey;
389
+ }
390
+ return signer.publicKey;
391
+ }
392
+ async signTransaction(tx) {
393
+ if (isKeypair(this.signer)) {
394
+ return this.signWithKeypair(tx, this.signer);
395
+ }
396
+ if (isAnchorProvider(this.signer)) {
397
+ return this.signer.wallet.signTransaction(tx);
398
+ }
399
+ return this.signer.signTransaction(tx);
400
+ }
401
+ async signAllTransactions(txs) {
402
+ if (isKeypair(this.signer)) {
403
+ return txs.map((tx) => this.signWithKeypair(tx, this.signer));
404
+ }
405
+ if (isAnchorProvider(this.signer)) {
406
+ return this.signer.wallet.signAllTransactions(txs);
407
+ }
408
+ return this.signer.signAllTransactions(txs);
409
+ }
410
+ signWithKeypair(tx, keypair) {
411
+ if (tx instanceof VersionedTransaction) {
412
+ tx.sign([keypair]);
413
+ } else {
414
+ tx.partialSign(keypair);
415
+ }
416
+ return tx;
417
+ }
418
+ }
419
+
420
+ // src/LoyalTransactionsClient.ts
421
+ function createProgram(provider) {
422
+ return new Program(IDL, provider);
423
+ }
424
+
425
+ class LoyalTransactionsClient {
426
+ program;
427
+ wallet;
428
+ constructor(program, wallet) {
429
+ this.program = program;
430
+ this.wallet = wallet;
431
+ }
432
+ static fromProvider(provider) {
433
+ const program = createProgram(provider);
434
+ const wallet = InternalWalletAdapter.from(provider);
435
+ return new LoyalTransactionsClient(program, wallet);
436
+ }
437
+ static from(connection, signer) {
438
+ const adapter = InternalWalletAdapter.from(signer);
439
+ const provider = new AnchorProvider(connection, adapter, {
440
+ commitment: "confirmed"
441
+ });
442
+ const program = createProgram(provider);
443
+ return new LoyalTransactionsClient(program, adapter);
444
+ }
445
+ static fromWallet(connection, wallet) {
446
+ return LoyalTransactionsClient.from(connection, wallet);
447
+ }
448
+ static fromKeypair(connection, keypair) {
449
+ return LoyalTransactionsClient.from(connection, keypair);
450
+ }
451
+ async deposit(params) {
452
+ const { username, amountLamports, commitment = "confirmed" } = params;
453
+ if (!username || username.length < 5 || username.length > 32) {
454
+ throw new Error("Username must be between 5 and 32 characters");
455
+ }
456
+ if (amountLamports <= 0) {
457
+ throw new Error("Amount must be greater than 0");
458
+ }
459
+ const depositor = this.wallet.publicKey;
460
+ const amountBN = new BN(amountLamports.toString());
461
+ const signature = await this.program.methods.depositForUsername(username, amountBN).accounts({
462
+ payer: depositor,
463
+ depositor
464
+ }).rpc({ commitment });
465
+ console.log("Transaction:", signature);
466
+ const deposit = await this.getDeposit(depositor, username);
467
+ console.log("Deposit:", deposit);
468
+ if (!deposit) {
469
+ throw new Error("Failed to fetch deposit account after transaction");
470
+ }
471
+ return {
472
+ signature,
473
+ deposit
474
+ };
475
+ }
476
+ async getDeposit(depositor, username) {
477
+ const [depositPda] = findDepositPda(depositor, username);
478
+ try {
479
+ const account = await this.program.account.deposit.fetch(depositPda);
480
+ return {
481
+ user: account.user,
482
+ username: account.username,
483
+ amount: account.amount.toNumber(),
484
+ lastNonce: account.lastNonce.toNumber(),
485
+ address: depositPda
486
+ };
487
+ } catch {
488
+ return null;
489
+ }
490
+ }
491
+ findDepositPda(depositor, username) {
492
+ return findDepositPda(depositor, username, PROGRAM_ID);
493
+ }
494
+ findVaultPda() {
495
+ return findVaultPda(PROGRAM_ID);
496
+ }
497
+ get publicKey() {
498
+ return this.wallet.publicKey;
499
+ }
500
+ getProgram() {
501
+ return this.program;
502
+ }
503
+ getProgramId() {
504
+ return PROGRAM_ID;
505
+ }
506
+ }
507
+ export {
508
+ solToLamports,
509
+ lamportsToSol,
510
+ isWalletLike,
511
+ isKeypair,
512
+ isAnchorProvider,
513
+ findVaultPda,
514
+ findDepositPda,
515
+ VAULT_SEED,
516
+ PROGRAM_ID,
517
+ LoyalTransactionsClient,
518
+ LAMPORTS_PER_SOL,
519
+ IDL,
520
+ DEPOSIT_SEED
521
+ };
@@ -0,0 +1,126 @@
1
+ import { Connection, PublicKey, Keypair } from "@solana/web3.js";
2
+ import { AnchorProvider, Program } from "@coral-xyz/anchor";
3
+ import { type TelegramTransfer } from "./idl";
4
+ import type { WalletSigner, WalletLike, DepositParams, DepositResult, DepositData } from "./types";
5
+ /**
6
+ * LoyalTransactionsClient - SDK for interacting with the Telegram Transfer program
7
+ *
8
+ * @example
9
+ * // Browser with wallet adapter
10
+ * const client = LoyalTransactionsClient.fromWallet(connection, walletAdapter);
11
+ *
12
+ * // Server-side with keypair
13
+ * const client = LoyalTransactionsClient.fromKeypair(connection, keypair);
14
+ *
15
+ * // Existing Anchor project
16
+ * const client = LoyalTransactionsClient.fromProvider(provider);
17
+ *
18
+ * // Deposit SOL for a username
19
+ * const result = await client.deposit({
20
+ * username: 'alice',
21
+ * amountLamports: 100_000_000, // 0.1 SOL
22
+ * });
23
+ */
24
+ export declare class LoyalTransactionsClient {
25
+ private readonly program;
26
+ private readonly wallet;
27
+ private constructor();
28
+ /**
29
+ * Create client from an AnchorProvider (for existing Anchor projects)
30
+ *
31
+ * @example
32
+ * const provider = AnchorProvider.env();
33
+ * const client = LoyalTransactionsClient.fromProvider(provider);
34
+ */
35
+ static fromProvider(provider: AnchorProvider): LoyalTransactionsClient;
36
+ /**
37
+ * Create client from any supported signer type
38
+ * Automatically detects the signer type and creates the appropriate client
39
+ *
40
+ * @example
41
+ * // Works with any signer type
42
+ * const client = LoyalTransactionsClient.from(connection, signer);
43
+ */
44
+ static from(connection: Connection, signer: WalletSigner): LoyalTransactionsClient;
45
+ /**
46
+ * Create client from a Connection and wallet adapter (for browser dApps)
47
+ *
48
+ * @example
49
+ * import { useConnection, useWallet } from '@solana/wallet-adapter-react';
50
+ *
51
+ * const { connection } = useConnection();
52
+ * const wallet = useWallet();
53
+ * const client = LoyalTransactionsClient.fromWallet(connection, wallet);
54
+ */
55
+ static fromWallet(connection: Connection, wallet: WalletLike): LoyalTransactionsClient;
56
+ /**
57
+ * Create client from a Connection and Keypair (for server-side scripts)
58
+ *
59
+ * @example
60
+ * const connection = new Connection('https://api.devnet.solana.com');
61
+ * const keypair = Keypair.fromSecretKey(secretKey);
62
+ * const client = LoyalTransactionsClient.fromKeypair(connection, keypair);
63
+ */
64
+ static fromKeypair(connection: Connection, keypair: Keypair): LoyalTransactionsClient;
65
+ /**
66
+ * Deposit SOL for a Telegram username
67
+ *
68
+ * Creates or tops up a deposit for the specified username.
69
+ * The deposit can later be claimed by the user who verifies
70
+ * ownership of the Telegram account.
71
+ *
72
+ * @param params - Deposit parameters
73
+ * @returns Transaction signature and updated deposit data
74
+ *
75
+ * @example
76
+ * const result = await client.deposit({
77
+ * username: 'alice',
78
+ * amountLamports: 100_000_000, // 0.1 SOL
79
+ * });
80
+ *
81
+ * console.log('Signature:', result.signature);
82
+ * console.log('Deposit amount:', result.deposit.amount);
83
+ */
84
+ deposit(params: DepositParams): Promise<DepositResult>;
85
+ /**
86
+ * Get deposit data for a specific depositor and username
87
+ *
88
+ * @param depositor - The depositor's public key
89
+ * @param username - The Telegram username
90
+ * @returns Deposit data or null if not found
91
+ *
92
+ * @example
93
+ * const deposit = await client.getDeposit(depositorPubkey, 'alice');
94
+ * if (deposit) {
95
+ * console.log('Amount:', deposit.amount);
96
+ * }
97
+ */
98
+ getDeposit(depositor: PublicKey, username: string): Promise<DepositData | null>;
99
+ /**
100
+ * Find the deposit PDA for a depositor and username
101
+ *
102
+ * @param depositor - The depositor's public key
103
+ * @param username - The Telegram username
104
+ * @returns [PDA address, bump seed]
105
+ */
106
+ findDepositPda(depositor: PublicKey, username: string): [PublicKey, number];
107
+ /**
108
+ * Find the vault PDA
109
+ *
110
+ * @returns [PDA address, bump seed]
111
+ */
112
+ findVaultPda(): [PublicKey, number];
113
+ /**
114
+ * Get the connected wallet's public key
115
+ */
116
+ get publicKey(): PublicKey;
117
+ /**
118
+ * Get the underlying Anchor program instance
119
+ * For advanced users who need direct program access
120
+ */
121
+ getProgram(): Program<TelegramTransfer>;
122
+ /**
123
+ * Get the program ID
124
+ */
125
+ getProgramId(): PublicKey;
126
+ }
@@ -0,0 +1,27 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ /**
3
+ * Telegram Transfer program ID
4
+ */
5
+ export declare const PROGRAM_ID: PublicKey;
6
+ /**
7
+ * PDA seed for deposit accounts
8
+ */
9
+ export declare const DEPOSIT_SEED = "deposit";
10
+ export declare const DEPOSIT_SEED_BYTES: Buffer;
11
+ /**
12
+ * PDA seed for vault account
13
+ */
14
+ export declare const VAULT_SEED = "vault";
15
+ export declare const VAULT_SEED_BYTES: Buffer;
16
+ /**
17
+ * Lamports per SOL (1 SOL = 1,000,000,000 lamports)
18
+ */
19
+ export declare const LAMPORTS_PER_SOL = 1000000000;
20
+ /**
21
+ * Convert SOL to lamports
22
+ */
23
+ export declare function solToLamports(sol: number): number;
24
+ /**
25
+ * Convert lamports to SOL
26
+ */
27
+ export declare function lamportsToSol(lamports: number): number;