@sudobility/contracts 1.14.1 → 1.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/artifacts/contracts/Mailer.sol/Mailer.d.ts +2 -2
  2. package/artifacts/contracts/Mailer.sol/Mailer.dbg.json +1 -1
  3. package/artifacts/contracts/Mailer.sol/Mailer.json +2 -2
  4. package/artifacts/contracts/MockUSDC.sol/MockUSDC.dbg.json +1 -1
  5. package/artifacts/contracts/interfaces/IERC20.sol/IERC20.dbg.json +1 -1
  6. package/dist/evm/src/evm/evm-mailer-client.d.ts +4 -0
  7. package/dist/evm/src/evm/evm-mailer-client.d.ts.map +1 -1
  8. package/dist/evm/src/evm/evm-mailer-client.js +43 -1
  9. package/dist/evm/src/evm/evm-mailer-client.js.map +1 -1
  10. package/dist/evm/typechain-types/factories/Mailer__factory.d.ts +1 -1
  11. package/dist/evm/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
  12. package/dist/evm/typechain-types/factories/Mailer__factory.js +1 -1
  13. package/dist/evm/typechain-types/factories/Mailer__factory.js.map +1 -1
  14. package/dist/solana/solana/solana-mailer-client.d.ts +9 -5
  15. package/dist/solana/solana/solana-mailer-client.d.ts.map +1 -1
  16. package/dist/solana/solana/solana-mailer-client.js +183 -145
  17. package/dist/solana/solana/solana-mailer-client.js.map +1 -1
  18. package/dist/unified/src/evm/evm-mailer-client.d.ts +4 -0
  19. package/dist/unified/src/evm/evm-mailer-client.d.ts.map +1 -1
  20. package/dist/unified/src/evm/evm-mailer-client.js +43 -1
  21. package/dist/unified/src/evm/evm-mailer-client.js.map +1 -1
  22. package/dist/unified/src/solana/solana-mailer-client.d.ts +9 -5
  23. package/dist/unified/src/solana/solana-mailer-client.d.ts.map +1 -1
  24. package/dist/unified/src/solana/solana-mailer-client.js +183 -145
  25. package/dist/unified/src/solana/solana-mailer-client.js.map +1 -1
  26. package/dist/unified/src/unified/onchain-mailer-client.d.ts +8 -0
  27. package/dist/unified/src/unified/onchain-mailer-client.d.ts.map +1 -1
  28. package/dist/unified/src/unified/onchain-mailer-client.js +55 -14
  29. package/dist/unified/src/unified/onchain-mailer-client.js.map +1 -1
  30. package/dist/unified/typechain-types/factories/Mailer__factory.d.ts +1 -1
  31. package/dist/unified/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
  32. package/dist/unified/typechain-types/factories/Mailer__factory.js +1 -1
  33. package/dist/unified/typechain-types/factories/Mailer__factory.js.map +1 -1
  34. package/package.json +1 -1
  35. package/programs/mailer/src/lib.rs +95 -24
  36. package/typechain-types/factories/Mailer__factory.ts +1 -1
@@ -8,22 +8,28 @@ var InstructionType;
8
8
  InstructionType[InstructionType["Initialize"] = 0] = "Initialize";
9
9
  InstructionType[InstructionType["Send"] = 1] = "Send";
10
10
  InstructionType[InstructionType["SendPrepared"] = 2] = "SendPrepared";
11
- InstructionType[InstructionType["SendThroughWebhook"] = 3] = "SendThroughWebhook";
12
- InstructionType[InstructionType["SendToEmail"] = 4] = "SendToEmail";
13
- InstructionType[InstructionType["SendPreparedToEmail"] = 5] = "SendPreparedToEmail";
11
+ InstructionType[InstructionType["SendToEmail"] = 3] = "SendToEmail";
12
+ InstructionType[InstructionType["SendPreparedToEmail"] = 4] = "SendPreparedToEmail";
13
+ InstructionType[InstructionType["SendThroughWebhook"] = 5] = "SendThroughWebhook";
14
14
  InstructionType[InstructionType["ClaimRecipientShare"] = 6] = "ClaimRecipientShare";
15
15
  InstructionType[InstructionType["ClaimOwnerShare"] = 7] = "ClaimOwnerShare";
16
- InstructionType[InstructionType["ClaimExpiredShares"] = 8] = "ClaimExpiredShares";
17
- InstructionType[InstructionType["SetFees"] = 9] = "SetFees";
18
- InstructionType[InstructionType["DelegateTo"] = 10] = "DelegateTo";
19
- InstructionType[InstructionType["RejectDelegation"] = 11] = "RejectDelegation";
16
+ InstructionType[InstructionType["SetFee"] = 8] = "SetFee";
17
+ InstructionType[InstructionType["DelegateTo"] = 9] = "DelegateTo";
18
+ InstructionType[InstructionType["RejectDelegation"] = 10] = "RejectDelegation";
19
+ InstructionType[InstructionType["SetDelegationFee"] = 11] = "SetDelegationFee";
20
20
  InstructionType[InstructionType["SetCustomFeePercentage"] = 12] = "SetCustomFeePercentage";
21
21
  InstructionType[InstructionType["ClearCustomFeePercentage"] = 13] = "ClearCustomFeePercentage";
22
22
  InstructionType[InstructionType["Pause"] = 14] = "Pause";
23
23
  InstructionType[InstructionType["Unpause"] = 15] = "Unpause";
24
- InstructionType[InstructionType["EmergencyUnpause"] = 16] = "EmergencyUnpause";
25
- InstructionType[InstructionType["DistributeClaimableFunds"] = 17] = "DistributeClaimableFunds";
24
+ InstructionType[InstructionType["DistributeClaimableFunds"] = 16] = "DistributeClaimableFunds";
25
+ InstructionType[InstructionType["ClaimExpiredShares"] = 17] = "ClaimExpiredShares";
26
+ InstructionType[InstructionType["EmergencyUnpause"] = 18] = "EmergencyUnpause";
27
+ InstructionType[InstructionType["SetFeePaused"] = 19] = "SetFeePaused";
26
28
  })(InstructionType || (InstructionType = {}));
29
+ const CLAIM_PDA_SEED = Buffer.from('claim');
30
+ const DELEGATION_PDA_SEED = Buffer.from('delegation');
31
+ const DISCOUNT_PDA_SEED = Buffer.from('discount');
32
+ const CLAIM_PERIOD_SECONDS = 60 * 24 * 60 * 60;
27
33
  // Instruction data encoding functions
28
34
  function encodeInitialize(usdcMint) {
29
35
  const data = Buffer.alloc(1 + 32);
@@ -70,43 +76,35 @@ function encodeSendPrepared(to, mailId, revenueShareToReceiver, resolveSenderToN
70
76
  data.writeUInt8(resolveSenderToName ? 1 : 0, offset);
71
77
  return data;
72
78
  }
73
- function encodeSendThroughWebhook(to, subject, body, webhookId, revenueShareToReceiver) {
74
- const subjectBytes = Buffer.from(subject, 'utf8');
75
- const bodyBytes = Buffer.from(body, 'utf8');
79
+ function encodeSendThroughWebhook(to, webhookId, revenueShareToReceiver, resolveSenderToName = false) {
76
80
  const webhookIdBytes = Buffer.from(webhookId, 'utf8');
77
- const data = Buffer.alloc(1 + 32 + 4 + subjectBytes.length + 4 + bodyBytes.length + 4 + webhookIdBytes.length + 1);
81
+ const data = Buffer.alloc(1 + 32 + 4 + webhookIdBytes.length + 1 + 1);
78
82
  let offset = 0;
79
83
  data.writeUInt8(InstructionType.SendThroughWebhook, offset);
80
84
  offset += 1;
81
85
  to.toBuffer().copy(data, offset);
82
86
  offset += 32;
83
- data.writeUInt32LE(subjectBytes.length, offset);
84
- offset += 4;
85
- subjectBytes.copy(data, offset);
86
- offset += subjectBytes.length;
87
- data.writeUInt32LE(bodyBytes.length, offset);
88
- offset += 4;
89
- bodyBytes.copy(data, offset);
90
- offset += bodyBytes.length;
91
87
  data.writeUInt32LE(webhookIdBytes.length, offset);
92
88
  offset += 4;
93
89
  webhookIdBytes.copy(data, offset);
94
90
  offset += webhookIdBytes.length;
95
91
  data.writeUInt8(revenueShareToReceiver ? 1 : 0, offset);
92
+ offset += 1;
93
+ data.writeUInt8(resolveSenderToName ? 1 : 0, offset);
96
94
  return data;
97
95
  }
98
- function encodeSendToEmail(emailHash, subject, body, payer, revenueShareToReceiver) {
99
- const emailHashBytes = Buffer.from(emailHash, 'utf8');
96
+ function encodeSendToEmail(toEmail, subject, body) {
97
+ const emailBytes = Buffer.from(toEmail, 'utf8');
100
98
  const subjectBytes = Buffer.from(subject, 'utf8');
101
99
  const bodyBytes = Buffer.from(body, 'utf8');
102
- const data = Buffer.alloc(1 + 4 + emailHashBytes.length + 4 + subjectBytes.length + 4 + bodyBytes.length + 32 + 1);
100
+ const data = Buffer.alloc(1 + 4 + emailBytes.length + 4 + subjectBytes.length + 4 + bodyBytes.length);
103
101
  let offset = 0;
104
102
  data.writeUInt8(InstructionType.SendToEmail, offset);
105
103
  offset += 1;
106
- data.writeUInt32LE(emailHashBytes.length, offset);
104
+ data.writeUInt32LE(emailBytes.length, offset);
107
105
  offset += 4;
108
- emailHashBytes.copy(data, offset);
109
- offset += emailHashBytes.length;
106
+ emailBytes.copy(data, offset);
107
+ offset += emailBytes.length;
110
108
  data.writeUInt32LE(subjectBytes.length, offset);
111
109
  offset += 4;
112
110
  subjectBytes.copy(data, offset);
@@ -115,36 +113,35 @@ function encodeSendToEmail(emailHash, subject, body, payer, revenueShareToReceiv
115
113
  offset += 4;
116
114
  bodyBytes.copy(data, offset);
117
115
  offset += bodyBytes.length;
118
- payer.toBuffer().copy(data, offset);
119
- offset += 32;
120
- data.writeUInt8(revenueShareToReceiver ? 1 : 0, offset);
121
116
  return data;
122
117
  }
123
- function encodeSendPreparedToEmail(emailHash, mailId, payer, revenueShareToReceiver) {
124
- const emailHashBytes = Buffer.from(emailHash, 'utf8');
118
+ function encodeSendPreparedToEmail(toEmail, mailId) {
119
+ const emailBytes = Buffer.from(toEmail, 'utf8');
125
120
  const mailIdBytes = Buffer.from(mailId, 'utf8');
126
- const data = Buffer.alloc(1 + 4 + emailHashBytes.length + 4 + mailIdBytes.length + 32 + 1);
121
+ const data = Buffer.alloc(1 + 4 + emailBytes.length + 4 + mailIdBytes.length);
127
122
  let offset = 0;
128
123
  data.writeUInt8(InstructionType.SendPreparedToEmail, offset);
129
124
  offset += 1;
130
- data.writeUInt32LE(emailHashBytes.length, offset);
125
+ data.writeUInt32LE(emailBytes.length, offset);
131
126
  offset += 4;
132
- emailHashBytes.copy(data, offset);
133
- offset += emailHashBytes.length;
127
+ emailBytes.copy(data, offset);
128
+ offset += emailBytes.length;
134
129
  data.writeUInt32LE(mailIdBytes.length, offset);
135
130
  offset += 4;
136
131
  mailIdBytes.copy(data, offset);
137
132
  offset += mailIdBytes.length;
138
- payer.toBuffer().copy(data, offset);
139
- offset += 32;
140
- data.writeUInt8(revenueShareToReceiver ? 1 : 0, offset);
141
133
  return data;
142
134
  }
143
- function encodeSetFees(sendFee, delegationFee) {
144
- const data = Buffer.alloc(1 + 8 + 8);
145
- data.writeUInt8(InstructionType.SetFees, 0);
135
+ function encodeSetFee(sendFee) {
136
+ const data = Buffer.alloc(1 + 8);
137
+ data.writeUInt8(InstructionType.SetFee, 0);
146
138
  data.writeBigUInt64LE(sendFee, 1);
147
- data.writeBigUInt64LE(delegationFee, 9);
139
+ return data;
140
+ }
141
+ function encodeSetDelegationFee(delegationFee) {
142
+ const data = Buffer.alloc(1 + 8);
143
+ data.writeUInt8(InstructionType.SetDelegationFee, 0);
144
+ data.writeBigUInt64LE(delegationFee, 1);
148
145
  return data;
149
146
  }
150
147
  function encodeDelegateTo(delegate) {
@@ -156,10 +153,9 @@ function encodeDelegateTo(delegate) {
156
153
  }
157
154
  return data;
158
155
  }
159
- function encodeRejectDelegation(delegatingAddress) {
160
- const data = Buffer.alloc(1 + 32);
156
+ function encodeRejectDelegation() {
157
+ const data = Buffer.alloc(1);
161
158
  data.writeUInt8(InstructionType.RejectDelegation, 0);
162
- delegatingAddress.toBuffer().copy(data, 1);
163
159
  return data;
164
160
  }
165
161
  function encodeSetCustomFeePercentage(account, percentage) {
@@ -184,18 +180,16 @@ function encodeClaimExpiredShares(recipient) {
184
180
  recipient.toBuffer().copy(data, 1);
185
181
  return data;
186
182
  }
187
- function encodeDistributeClaimableFunds(recipients) {
188
- const recipientCount = recipients.length;
189
- const data = Buffer.alloc(1 + 4 + recipientCount * 32);
190
- let offset = 0;
191
- data.writeUInt8(InstructionType.DistributeClaimableFunds, offset);
192
- offset += 1;
193
- data.writeUInt32LE(recipientCount, offset);
194
- offset += 4;
195
- for (const recipient of recipients) {
196
- recipient.toBuffer().copy(data, offset);
197
- offset += 32;
198
- }
183
+ function encodeDistributeClaimableFunds(recipient) {
184
+ const data = Buffer.alloc(1 + 32);
185
+ data.writeUInt8(InstructionType.DistributeClaimableFunds, 0);
186
+ recipient.toBuffer().copy(data, 1);
187
+ return data;
188
+ }
189
+ function encodeSetFeePaused(feePaused) {
190
+ const data = Buffer.alloc(1 + 1);
191
+ data.writeUInt8(InstructionType.SetFeePaused, 0);
192
+ data.writeUInt8(feePaused ? 1 : 0, 1);
199
193
  return data;
200
194
  }
201
195
  /**
@@ -394,7 +388,7 @@ export class SolanaMailerClient {
394
388
  /**
395
389
  * Send a message with optional revenue sharing
396
390
  */
397
- async send(connectedWallet, chainInfo, to, subject, body, revenueShareToReceiver, computeOptions) {
391
+ async send(connectedWallet, chainInfo, to, subject, body, revenueShareToReceiver, resolveSenderToName = false, computeOptions) {
398
392
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
399
393
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
400
394
  if (!chainInfo.usdcAddress) {
@@ -402,24 +396,22 @@ export class SolanaMailerClient {
402
396
  }
403
397
  const usdcMint = new PublicKey(chainInfo.usdcAddress);
404
398
  const toPubkey = typeof to === 'string' ? new PublicKey(to) : to;
405
- // Get token accounts
406
399
  const senderTokenAccount = getAssociatedTokenAddressSync(usdcMint, connectedWallet.wallet.publicKey, false, TOKEN_PROGRAM_ID);
407
400
  const mailerTokenAccount = getAssociatedTokenAddressSync(usdcMint, mailerStatePda, true, TOKEN_PROGRAM_ID);
408
- const [recipientInfo] = PublicKey.findProgramAddressSync([Buffer.from('recipient_info'), toPubkey.toBuffer()], programId);
401
+ const [recipientClaimPda] = PublicKey.findProgramAddressSync([CLAIM_PDA_SEED, toPubkey.toBuffer()], programId);
409
402
  const keys = [
410
403
  { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: true },
411
- { pubkey: toPubkey, isSigner: false, isWritable: false },
404
+ { pubkey: recipientClaimPda, isSigner: false, isWritable: true },
412
405
  { pubkey: mailerStatePda, isSigner: false, isWritable: true },
413
406
  { pubkey: senderTokenAccount, isSigner: false, isWritable: true },
414
407
  { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
415
- { pubkey: recipientInfo, isSigner: false, isWritable: true },
416
408
  { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
417
409
  { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
418
410
  ];
419
411
  const instruction = new TransactionInstruction({
420
412
  programId,
421
413
  keys,
422
- data: encodeSend(toPubkey, subject, body, revenueShareToReceiver),
414
+ data: encodeSend(toPubkey, subject, body, revenueShareToReceiver, resolveSenderToName),
423
415
  });
424
416
  const transaction = new Transaction().add(instruction);
425
417
  // Check if mailer token account exists, create if not
@@ -432,7 +424,7 @@ export class SolanaMailerClient {
432
424
  /**
433
425
  * Send a prepared message
434
426
  */
435
- async sendPrepared(connectedWallet, chainInfo, to, mailId, revenueShareToReceiver, computeOptions) {
427
+ async sendPrepared(connectedWallet, chainInfo, to, mailId, revenueShareToReceiver, resolveSenderToName = false, computeOptions) {
436
428
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
437
429
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
438
430
  if (!chainInfo.usdcAddress) {
@@ -442,21 +434,20 @@ export class SolanaMailerClient {
442
434
  const toPubkey = typeof to === 'string' ? new PublicKey(to) : to;
443
435
  const senderTokenAccount = getAssociatedTokenAddressSync(usdcMint, connectedWallet.wallet.publicKey, false, TOKEN_PROGRAM_ID);
444
436
  const mailerTokenAccount = getAssociatedTokenAddressSync(usdcMint, mailerStatePda, true, TOKEN_PROGRAM_ID);
445
- const [recipientInfo] = PublicKey.findProgramAddressSync([Buffer.from('recipient_info'), toPubkey.toBuffer()], programId);
437
+ const [recipientClaimPda] = PublicKey.findProgramAddressSync([CLAIM_PDA_SEED, toPubkey.toBuffer()], programId);
446
438
  const keys = [
447
439
  { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: true },
448
- { pubkey: toPubkey, isSigner: false, isWritable: false },
440
+ { pubkey: recipientClaimPda, isSigner: false, isWritable: true },
449
441
  { pubkey: mailerStatePda, isSigner: false, isWritable: true },
450
442
  { pubkey: senderTokenAccount, isSigner: false, isWritable: true },
451
443
  { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
452
- { pubkey: recipientInfo, isSigner: false, isWritable: true },
453
444
  { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
454
445
  { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
455
446
  ];
456
447
  const instruction = new TransactionInstruction({
457
448
  programId,
458
449
  keys,
459
- data: encodeSendPrepared(toPubkey, mailId, revenueShareToReceiver),
450
+ data: encodeSendPrepared(toPubkey, mailId, revenueShareToReceiver, resolveSenderToName),
460
451
  });
461
452
  const transaction = new Transaction().add(instruction);
462
453
  // Check if mailer token account exists, create if not
@@ -469,7 +460,7 @@ export class SolanaMailerClient {
469
460
  /**
470
461
  * Send through webhook
471
462
  */
472
- async sendThroughWebhook(connectedWallet, chainInfo, to, subject, body, webhookId, revenueShareToReceiver, computeOptions) {
463
+ async sendThroughWebhook(connectedWallet, chainInfo, to, webhookId, revenueShareToReceiver, resolveSenderToName = false, computeOptions) {
473
464
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
474
465
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
475
466
  if (!chainInfo.usdcAddress) {
@@ -479,21 +470,20 @@ export class SolanaMailerClient {
479
470
  const toPubkey = typeof to === 'string' ? new PublicKey(to) : to;
480
471
  const senderTokenAccount = getAssociatedTokenAddressSync(usdcMint, connectedWallet.wallet.publicKey, false, TOKEN_PROGRAM_ID);
481
472
  const mailerTokenAccount = getAssociatedTokenAddressSync(usdcMint, mailerStatePda, true, TOKEN_PROGRAM_ID);
482
- const [recipientInfo] = PublicKey.findProgramAddressSync([Buffer.from('recipient_info'), toPubkey.toBuffer()], programId);
473
+ const [recipientClaimPda] = PublicKey.findProgramAddressSync([CLAIM_PDA_SEED, toPubkey.toBuffer()], programId);
483
474
  const keys = [
484
475
  { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: true },
485
- { pubkey: toPubkey, isSigner: false, isWritable: false },
476
+ { pubkey: recipientClaimPda, isSigner: false, isWritable: true },
486
477
  { pubkey: mailerStatePda, isSigner: false, isWritable: true },
487
478
  { pubkey: senderTokenAccount, isSigner: false, isWritable: true },
488
479
  { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
489
- { pubkey: recipientInfo, isSigner: false, isWritable: true },
490
480
  { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
491
481
  { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
492
482
  ];
493
483
  const instruction = new TransactionInstruction({
494
484
  programId,
495
485
  keys,
496
- data: encodeSendThroughWebhook(toPubkey, subject, body, webhookId, revenueShareToReceiver),
486
+ data: encodeSendThroughWebhook(toPubkey, webhookId, revenueShareToReceiver, resolveSenderToName),
497
487
  });
498
488
  const transaction = new Transaction().add(instruction);
499
489
  const accountInfo = await connection.getAccountInfo(mailerTokenAccount);
@@ -505,14 +495,13 @@ export class SolanaMailerClient {
505
495
  /**
506
496
  * Send to email address
507
497
  */
508
- async sendToEmail(emailHash, subject, body, payer, revenueShareToReceiver, connectedWallet, chainInfo, computeOptions) {
498
+ async sendToEmail(emailHash, subject, body, _payer, _revenueShareToReceiver, connectedWallet, chainInfo, computeOptions) {
509
499
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
510
500
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
511
501
  if (!chainInfo.usdcAddress) {
512
502
  throw new Error(`No USDC mint configured for ${chainInfo.name}`);
513
503
  }
514
504
  const usdcMint = new PublicKey(chainInfo.usdcAddress);
515
- const payerPubkey = typeof payer === 'string' ? new PublicKey(payer) : payer;
516
505
  const senderTokenAccount = getAssociatedTokenAddressSync(usdcMint, connectedWallet.wallet.publicKey, false, TOKEN_PROGRAM_ID);
517
506
  const mailerTokenAccount = getAssociatedTokenAddressSync(usdcMint, mailerStatePda, true, TOKEN_PROGRAM_ID);
518
507
  const keys = [
@@ -521,12 +510,11 @@ export class SolanaMailerClient {
521
510
  { pubkey: senderTokenAccount, isSigner: false, isWritable: true },
522
511
  { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
523
512
  { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
524
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
525
513
  ];
526
514
  const instruction = new TransactionInstruction({
527
515
  programId,
528
516
  keys,
529
- data: encodeSendToEmail(emailHash, subject, body, payerPubkey, revenueShareToReceiver),
517
+ data: encodeSendToEmail(emailHash, subject, body),
530
518
  });
531
519
  const transaction = new Transaction().add(instruction);
532
520
  const accountInfo = await connection.getAccountInfo(mailerTokenAccount);
@@ -538,14 +526,13 @@ export class SolanaMailerClient {
538
526
  /**
539
527
  * Send prepared to email address
540
528
  */
541
- async sendPreparedToEmail(emailHash, mailId, payer, revenueShareToReceiver, connectedWallet, chainInfo, computeOptions) {
529
+ async sendPreparedToEmail(emailHash, mailId, _payer, _revenueShareToReceiver, connectedWallet, chainInfo, computeOptions) {
542
530
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
543
531
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
544
532
  if (!chainInfo.usdcAddress) {
545
533
  throw new Error(`No USDC mint configured for ${chainInfo.name}`);
546
534
  }
547
535
  const usdcMint = new PublicKey(chainInfo.usdcAddress);
548
- const payerPubkey = typeof payer === 'string' ? new PublicKey(payer) : payer;
549
536
  const senderTokenAccount = getAssociatedTokenAddressSync(usdcMint, connectedWallet.wallet.publicKey, false, TOKEN_PROGRAM_ID);
550
537
  const mailerTokenAccount = getAssociatedTokenAddressSync(usdcMint, mailerStatePda, true, TOKEN_PROGRAM_ID);
551
538
  const keys = [
@@ -554,12 +541,11 @@ export class SolanaMailerClient {
554
541
  { pubkey: senderTokenAccount, isSigner: false, isWritable: true },
555
542
  { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
556
543
  { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
557
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
558
544
  ];
559
545
  const instruction = new TransactionInstruction({
560
546
  programId,
561
547
  keys,
562
- data: encodeSendPreparedToEmail(emailHash, mailId, payerPubkey, revenueShareToReceiver),
548
+ data: encodeSendPreparedToEmail(emailHash, mailId),
563
549
  });
564
550
  const transaction = new Transaction().add(instruction);
565
551
  const accountInfo = await connection.getAccountInfo(mailerTokenAccount);
@@ -580,13 +566,13 @@ export class SolanaMailerClient {
580
566
  const usdcMint = new PublicKey(chainInfo.usdcAddress);
581
567
  const recipientTokenAccount = getAssociatedTokenAddressSync(usdcMint, connectedWallet.wallet.publicKey, false, TOKEN_PROGRAM_ID);
582
568
  const mailerTokenAccount = getAssociatedTokenAddressSync(usdcMint, mailerStatePda, true, TOKEN_PROGRAM_ID);
583
- const [recipientInfo] = PublicKey.findProgramAddressSync([Buffer.from('recipient_info'), connectedWallet.wallet.publicKey.toBuffer()], programId);
569
+ const [recipientClaimPda] = PublicKey.findProgramAddressSync([CLAIM_PDA_SEED, connectedWallet.wallet.publicKey.toBuffer()], programId);
584
570
  const keys = [
585
571
  { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: true },
572
+ { pubkey: recipientClaimPda, isSigner: false, isWritable: true },
586
573
  { pubkey: mailerStatePda, isSigner: false, isWritable: true },
587
574
  { pubkey: recipientTokenAccount, isSigner: false, isWritable: true },
588
575
  { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
589
- { pubkey: recipientInfo, isSigner: false, isWritable: true },
590
576
  { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
591
577
  ];
592
578
  const instruction = new TransactionInstruction({
@@ -631,11 +617,11 @@ export class SolanaMailerClient {
631
617
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
632
618
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
633
619
  const recipientPubkey = typeof recipient === 'string' ? new PublicKey(recipient) : recipient;
634
- const [recipientInfo] = PublicKey.findProgramAddressSync([Buffer.from('recipient_info'), recipientPubkey.toBuffer()], programId);
620
+ const [recipientClaimPda] = PublicKey.findProgramAddressSync([CLAIM_PDA_SEED, recipientPubkey.toBuffer()], programId);
635
621
  const keys = [
636
622
  { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: true },
637
623
  { pubkey: mailerStatePda, isSigner: false, isWritable: true },
638
- { pubkey: recipientInfo, isSigner: false, isWritable: true },
624
+ { pubkey: recipientClaimPda, isSigner: false, isWritable: true },
639
625
  ];
640
626
  const instruction = new TransactionInstruction({
641
627
  programId,
@@ -660,13 +646,13 @@ export class SolanaMailerClient {
660
646
  : null;
661
647
  const senderTokenAccount = getAssociatedTokenAddressSync(usdcMint, connectedWallet.wallet.publicKey, false, TOKEN_PROGRAM_ID);
662
648
  const mailerTokenAccount = getAssociatedTokenAddressSync(usdcMint, mailerStatePda, true, TOKEN_PROGRAM_ID);
663
- const [delegatorInfo] = PublicKey.findProgramAddressSync([Buffer.from('delegator_info'), connectedWallet.wallet.publicKey.toBuffer()], programId);
649
+ const [delegationPda] = PublicKey.findProgramAddressSync([DELEGATION_PDA_SEED, connectedWallet.wallet.publicKey.toBuffer()], programId);
664
650
  const keys = [
665
651
  { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: true },
652
+ { pubkey: delegationPda, isSigner: false, isWritable: true },
666
653
  { pubkey: mailerStatePda, isSigner: false, isWritable: true },
667
654
  { pubkey: senderTokenAccount, isSigner: false, isWritable: true },
668
655
  { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
669
- { pubkey: delegatorInfo, isSigner: false, isWritable: true },
670
656
  { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
671
657
  { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
672
658
  ];
@@ -687,17 +673,18 @@ export class SolanaMailerClient {
687
673
  */
688
674
  async rejectDelegation(connectedWallet, chainInfo, delegatingAddress, computeOptions) {
689
675
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
690
- const { programId } = this.getProgramAddresses(chainInfo);
676
+ const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
691
677
  const delegatorPubkey = typeof delegatingAddress === 'string' ? new PublicKey(delegatingAddress) : delegatingAddress;
692
- const [delegatorInfo] = PublicKey.findProgramAddressSync([Buffer.from('delegator_info'), delegatorPubkey.toBuffer()], programId);
678
+ const [delegationPda] = PublicKey.findProgramAddressSync([DELEGATION_PDA_SEED, delegatorPubkey.toBuffer()], programId);
693
679
  const keys = [
694
680
  { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: false },
695
- { pubkey: delegatorInfo, isSigner: false, isWritable: true },
681
+ { pubkey: delegationPda, isSigner: false, isWritable: true },
682
+ { pubkey: mailerStatePda, isSigner: false, isWritable: false },
696
683
  ];
697
684
  const instruction = new TransactionInstruction({
698
685
  programId,
699
686
  keys,
700
- data: encodeRejectDelegation(delegatorPubkey),
687
+ data: encodeRejectDelegation(),
701
688
  });
702
689
  const transaction = new Transaction().add(instruction);
703
690
  return await this.sendTransaction(transaction, connectedWallet.wallet, connection, undefined, computeOptions);
@@ -708,16 +695,24 @@ export class SolanaMailerClient {
708
695
  async setFees(connectedWallet, chainInfo, sendFee, delegationFee, computeOptions) {
709
696
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
710
697
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
711
- const keys = [
712
- { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: false },
713
- { pubkey: mailerStatePda, isSigner: false, isWritable: true },
714
- ];
715
- const instruction = new TransactionInstruction({
698
+ const ownerKey = connectedWallet.wallet.publicKey;
699
+ const setSendFeeIx = new TransactionInstruction({
716
700
  programId,
717
- keys,
718
- data: encodeSetFees(BigInt(sendFee), BigInt(delegationFee)),
701
+ keys: [
702
+ { pubkey: ownerKey, isSigner: true, isWritable: false },
703
+ { pubkey: mailerStatePda, isSigner: false, isWritable: true },
704
+ ],
705
+ data: encodeSetFee(BigInt(sendFee)),
719
706
  });
720
- const transaction = new Transaction().add(instruction);
707
+ const setDelegationFeeIx = new TransactionInstruction({
708
+ programId,
709
+ keys: [
710
+ { pubkey: ownerKey, isSigner: true, isWritable: false },
711
+ { pubkey: mailerStatePda, isSigner: false, isWritable: true },
712
+ ],
713
+ data: encodeSetDelegationFee(BigInt(delegationFee)),
714
+ });
715
+ const transaction = new Transaction().add(setSendFeeIx, setDelegationFeeIx);
721
716
  return await this.sendTransaction(transaction, connectedWallet.wallet, connection, undefined, computeOptions);
722
717
  }
723
718
  /**
@@ -727,11 +722,14 @@ export class SolanaMailerClient {
727
722
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
728
723
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
729
724
  const accountPubkey = typeof account === 'string' ? new PublicKey(account) : account;
730
- const [customFeeInfo] = PublicKey.findProgramAddressSync([Buffer.from('custom_fee'), accountPubkey.toBuffer()], programId);
725
+ const [discountPda] = PublicKey.findProgramAddressSync([DISCOUNT_PDA_SEED, accountPubkey.toBuffer()], programId);
726
+ const ownerKey = connectedWallet.wallet.publicKey;
731
727
  const keys = [
732
- { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: true },
728
+ { pubkey: ownerKey, isSigner: true, isWritable: false },
733
729
  { pubkey: mailerStatePda, isSigner: false, isWritable: false },
734
- { pubkey: customFeeInfo, isSigner: false, isWritable: true },
730
+ { pubkey: discountPda, isSigner: false, isWritable: true },
731
+ { pubkey: accountPubkey, isSigner: false, isWritable: false },
732
+ { pubkey: ownerKey, isSigner: true, isWritable: true },
735
733
  { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
736
734
  ];
737
735
  const instruction = new TransactionInstruction({
@@ -749,11 +747,11 @@ export class SolanaMailerClient {
749
747
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
750
748
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
751
749
  const accountPubkey = typeof account === 'string' ? new PublicKey(account) : account;
752
- const [customFeeInfo] = PublicKey.findProgramAddressSync([Buffer.from('custom_fee'), accountPubkey.toBuffer()], programId);
750
+ const [discountPda] = PublicKey.findProgramAddressSync([DISCOUNT_PDA_SEED, accountPubkey.toBuffer()], programId);
753
751
  const keys = [
754
752
  { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: false },
755
753
  { pubkey: mailerStatePda, isSigner: false, isWritable: false },
756
- { pubkey: customFeeInfo, isSigner: false, isWritable: true },
754
+ { pubkey: discountPda, isSigner: false, isWritable: true },
757
755
  ];
758
756
  const instruction = new TransactionInstruction({
759
757
  programId,
@@ -769,16 +767,33 @@ export class SolanaMailerClient {
769
767
  async pause(connectedWallet, chainInfo, computeOptions) {
770
768
  const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
771
769
  const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
770
+ if (!chainInfo.usdcAddress) {
771
+ throw new Error(`No USDC mint configured for ${chainInfo.name}`);
772
+ }
773
+ const usdcMint = new PublicKey(chainInfo.usdcAddress);
774
+ const ownerTokenAccount = getAssociatedTokenAddressSync(usdcMint, connectedWallet.wallet.publicKey, false, TOKEN_PROGRAM_ID);
775
+ const mailerTokenAccount = getAssociatedTokenAddressSync(usdcMint, mailerStatePda, true, TOKEN_PROGRAM_ID);
776
+ const transaction = new Transaction();
777
+ const mailerTokenInfo = await connection.getAccountInfo(mailerTokenAccount);
778
+ if (!mailerTokenInfo) {
779
+ transaction.add(createAssociatedTokenAccountInstruction(connectedWallet.wallet.publicKey, mailerTokenAccount, mailerStatePda, usdcMint));
780
+ }
781
+ const ownerTokenInfo = await connection.getAccountInfo(ownerTokenAccount);
782
+ if (!ownerTokenInfo) {
783
+ transaction.add(createAssociatedTokenAccountInstruction(connectedWallet.wallet.publicKey, ownerTokenAccount, connectedWallet.wallet.publicKey, usdcMint));
784
+ }
772
785
  const keys = [
773
786
  { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: false },
774
787
  { pubkey: mailerStatePda, isSigner: false, isWritable: true },
788
+ { pubkey: ownerTokenAccount, isSigner: false, isWritable: true },
789
+ { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
790
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
775
791
  ];
776
- const instruction = new TransactionInstruction({
792
+ transaction.add(new TransactionInstruction({
777
793
  programId,
778
794
  keys,
779
795
  data: Buffer.from([InstructionType.Pause]),
780
- });
781
- const transaction = new Transaction().add(instruction);
796
+ }));
782
797
  return await this.sendTransaction(transaction, connectedWallet.wallet, connection, undefined, computeOptions);
783
798
  }
784
799
  /**
@@ -817,6 +832,24 @@ export class SolanaMailerClient {
817
832
  const transaction = new Transaction().add(instruction);
818
833
  return await this.sendTransaction(transaction, connectedWallet.wallet, connection, undefined, computeOptions);
819
834
  }
835
+ /**
836
+ * Set fee paused state (owner only)
837
+ */
838
+ async setFeePaused(feePaused, connectedWallet, chainInfo, computeOptions) {
839
+ const connection = await this.getOrCreateConnection(chainInfo, connectedWallet.connection);
840
+ const { programId, mailerStatePda } = this.getProgramAddresses(chainInfo);
841
+ const keys = [
842
+ { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: false },
843
+ { pubkey: mailerStatePda, isSigner: false, isWritable: true },
844
+ ];
845
+ const instruction = new TransactionInstruction({
846
+ programId,
847
+ keys,
848
+ data: encodeSetFeePaused(feePaused),
849
+ });
850
+ const transaction = new Transaction().add(instruction);
851
+ return await this.sendTransaction(transaction, connectedWallet.wallet, connection, undefined, computeOptions);
852
+ }
820
853
  /**
821
854
  * Distribute claimable funds when paused
822
855
  */
@@ -829,26 +862,31 @@ export class SolanaMailerClient {
829
862
  const usdcMint = new PublicKey(chainInfo.usdcAddress);
830
863
  const recipientPubkeys = recipients.map(r => typeof r === 'string' ? new PublicKey(r) : r);
831
864
  const mailerTokenAccount = getAssociatedTokenAddressSync(usdcMint, mailerStatePda, true, TOKEN_PROGRAM_ID);
832
- // Build keys array
833
- const keys = [
834
- { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: false },
835
- { pubkey: mailerStatePda, isSigner: false, isWritable: true },
836
- { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
837
- { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
838
- ];
839
- // Add recipient info and token accounts
865
+ const transaction = new Transaction();
866
+ const mailerTokenInfo = await connection.getAccountInfo(mailerTokenAccount);
867
+ if (!mailerTokenInfo) {
868
+ transaction.add(createAssociatedTokenAccountInstruction(connectedWallet.wallet.publicKey, mailerTokenAccount, mailerStatePda, usdcMint));
869
+ }
840
870
  for (const recipient of recipientPubkeys) {
841
- const [recipientInfo] = PublicKey.findProgramAddressSync([Buffer.from('recipient_info'), recipient.toBuffer()], programId);
871
+ const [recipientClaimPda] = PublicKey.findProgramAddressSync([CLAIM_PDA_SEED, recipient.toBuffer()], programId);
842
872
  const recipientTokenAccount = getAssociatedTokenAddressSync(usdcMint, recipient, false, TOKEN_PROGRAM_ID);
843
- keys.push({ pubkey: recipientInfo, isSigner: false, isWritable: true });
844
- keys.push({ pubkey: recipientTokenAccount, isSigner: false, isWritable: true });
873
+ const recipientTokenInfo = await connection.getAccountInfo(recipientTokenAccount);
874
+ if (!recipientTokenInfo) {
875
+ transaction.add(createAssociatedTokenAccountInstruction(connectedWallet.wallet.publicKey, recipientTokenAccount, recipient, usdcMint));
876
+ }
877
+ transaction.add(new TransactionInstruction({
878
+ programId,
879
+ keys: [
880
+ { pubkey: connectedWallet.wallet.publicKey, isSigner: true, isWritable: false },
881
+ { pubkey: mailerStatePda, isSigner: false, isWritable: true },
882
+ { pubkey: recipientClaimPda, isSigner: false, isWritable: true },
883
+ { pubkey: recipientTokenAccount, isSigner: false, isWritable: true },
884
+ { pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
885
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
886
+ ],
887
+ data: encodeDistributeClaimableFunds(recipient),
888
+ }));
845
889
  }
846
- const instruction = new TransactionInstruction({
847
- programId,
848
- keys,
849
- data: encodeDistributeClaimableFunds(recipientPubkeys),
850
- });
851
- const transaction = new Transaction().add(instruction);
852
890
  return await this.sendTransaction(transaction, connectedWallet.wallet, connection, undefined, computeOptions);
853
891
  }
854
892
  // ============= Read Methods =============
@@ -864,8 +902,8 @@ export class SolanaMailerClient {
864
902
  }
865
903
  // Parse the state data
866
904
  const data = accountInfo.data;
867
- const sendFee = data.readBigUInt64LE(41); // After discriminator(8) + owner(32) + paused(1)
868
- const delegationFee = data.readBigUInt64LE(49);
905
+ const sendFee = data.readBigUInt64LE(8 + 32 + 32); // After discriminator + owner + mint
906
+ const delegationFee = data.readBigUInt64LE(8 + 32 + 32 + 8);
869
907
  return {
870
908
  sendFee,
871
909
  delegationFee,
@@ -892,22 +930,22 @@ export class SolanaMailerClient {
892
930
  const conn = await this.getOrCreateConnection(chainInfo, connection);
893
931
  const { programId } = this.getProgramAddresses(chainInfo);
894
932
  const recipientPubkey = typeof recipient === 'string' ? new PublicKey(recipient) : recipient;
895
- const [recipientInfo] = PublicKey.findProgramAddressSync([Buffer.from('recipient_info'), recipientPubkey.toBuffer()], programId);
896
- const accountInfo = await conn.getAccountInfo(recipientInfo);
933
+ const [recipientClaimPda] = PublicKey.findProgramAddressSync([CLAIM_PDA_SEED, recipientPubkey.toBuffer()], programId);
934
+ const accountInfo = await conn.getAccountInfo(recipientClaimPda);
897
935
  if (!accountInfo || !accountInfo.data) {
898
936
  return null;
899
937
  }
900
938
  // Parse the recipient info data
901
939
  const data = accountInfo.data;
902
- const amount = data.readBigUInt64LE(8); // After discriminator
903
- const expiresAt = data.readBigInt64LE(16);
904
- // Check if expired
940
+ const amount = data.readBigUInt64LE(8 + 32); // discriminator + recipient
941
+ const timestamp = Number(data.readBigInt64LE(8 + 32 + 8)); // after amount
942
+ const expiresAt = timestamp + CLAIM_PERIOD_SECONDS;
905
943
  const now = Math.floor(Date.now() / 1000);
906
- const isExpired = Number(expiresAt) > 0 && Number(expiresAt) < now;
944
+ const isExpired = timestamp > 0 && now > expiresAt;
907
945
  return {
908
946
  amount: Number(amount),
909
- timestamp: Number(expiresAt), // Using expiresAt as timestamp
910
- expiresAt: Number(expiresAt),
947
+ timestamp,
948
+ expiresAt,
911
949
  recipient: recipient instanceof PublicKey ? recipient.toBase58() : recipient,
912
950
  isExpired,
913
951
  };
@@ -924,7 +962,7 @@ export class SolanaMailerClient {
924
962
  }
925
963
  // Parse the state data
926
964
  const data = accountInfo.data;
927
- const ownerClaimable = data.readBigUInt64LE(57); // After discriminator(8) + owner(32) + paused(1) + sendFee(8) + delegationFee(8)
965
+ const ownerClaimable = data.readBigUInt64LE(8 + 32 + 32 + 8 + 8); // After discriminator + owner + mint + sendFee + delegationFee
928
966
  return Number(ownerClaimable);
929
967
  }
930
968
  /**
@@ -934,19 +972,19 @@ export class SolanaMailerClient {
934
972
  const conn = await this.getOrCreateConnection(chainInfo, connection);
935
973
  const { programId } = this.getProgramAddresses(chainInfo);
936
974
  const addressPubkey = typeof address === 'string' ? new PublicKey(address) : address;
937
- const [delegatorInfo] = PublicKey.findProgramAddressSync([Buffer.from('delegator_info'), addressPubkey.toBuffer()], programId);
938
- const accountInfo = await conn.getAccountInfo(delegatorInfo);
975
+ const [delegationPda] = PublicKey.findProgramAddressSync([DELEGATION_PDA_SEED, addressPubkey.toBuffer()], programId);
976
+ const accountInfo = await conn.getAccountInfo(delegationPda);
939
977
  if (!accountInfo || !accountInfo.data) {
940
978
  return null;
941
979
  }
942
980
  // Parse the delegatingAddress info data
943
981
  const data = accountInfo.data;
944
- const hasDelegate = data.readUInt8(8) === 1; // After discriminator
982
+ const hasDelegate = data.readUInt8(8 + 32) === 1; // After discriminator + delegator
945
983
  if (!hasDelegate) {
946
984
  return null;
947
985
  }
948
986
  // Read delegate pubkey
949
- const delegateBytes = data.slice(9, 41); // 32 bytes for pubkey
987
+ const delegateBytes = data.slice(8 + 32 + 1, 8 + 32 + 1 + 32); // 32 bytes for pubkey
950
988
  return new PublicKey(delegateBytes);
951
989
  }
952
990
  /**
@@ -956,15 +994,15 @@ export class SolanaMailerClient {
956
994
  const conn = await this.getOrCreateConnection(chainInfo, connection);
957
995
  const { programId } = this.getProgramAddresses(chainInfo);
958
996
  const accountPubkey = typeof account === 'string' ? new PublicKey(account) : account;
959
- const [customFeeInfo] = PublicKey.findProgramAddressSync([Buffer.from('custom_fee'), accountPubkey.toBuffer()], programId);
960
- const accountInfo = await conn.getAccountInfo(customFeeInfo);
997
+ const [discountPda] = PublicKey.findProgramAddressSync([DISCOUNT_PDA_SEED, accountPubkey.toBuffer()], programId);
998
+ const accountInfo = await conn.getAccountInfo(discountPda);
961
999
  if (!accountInfo || !accountInfo.data) {
962
1000
  return 100; // Default to 100% if no custom fee set
963
1001
  }
964
1002
  // Parse the custom fee data
965
1003
  const data = accountInfo.data;
966
- const percentage = data.readUInt8(8); // After discriminator
967
- return percentage;
1004
+ const discount = data.readUInt8(8 + 32); // After discriminator + account pubkey
1005
+ return 100 - discount;
968
1006
  }
969
1007
  /**
970
1008
  * Check if the program is paused
@@ -978,7 +1016,7 @@ export class SolanaMailerClient {
978
1016
  }
979
1017
  // Parse the state data
980
1018
  const data = accountInfo.data;
981
- const paused = data.readUInt8(40); // After discriminator(8) + owner(32)
1019
+ const paused = data.readUInt8(8 + 32 + 32 + 8 + 8 + 8); // After all state fields up to owner_claimable
982
1020
  return paused === 1;
983
1021
  }
984
1022
  /**