@sudobility/contracts 1.11.1 → 1.12.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/artifacts/contracts/Mailer.sol/Mailer.d.ts +120 -2
- package/artifacts/contracts/Mailer.sol/Mailer.dbg.json +1 -1
- package/artifacts/contracts/Mailer.sol/Mailer.json +120 -2
- package/artifacts/contracts/MockUSDC.sol/MockUSDC.dbg.json +1 -1
- package/artifacts/contracts/interfaces/IERC20.sol/IERC20.dbg.json +1 -1
- package/dist/evm/src/evm/index.d.ts +1 -1
- package/dist/evm/src/evm/index.d.ts.map +1 -1
- package/dist/evm/src/evm/index.js +1 -1
- package/dist/evm/src/evm/index.js.map +1 -1
- package/dist/evm/src/evm/mailer-client.d.ts +936 -180
- package/dist/evm/src/evm/mailer-client.d.ts.map +1 -1
- package/dist/evm/src/evm/mailer-client.js +451 -249
- package/dist/evm/src/evm/mailer-client.js.map +1 -1
- package/dist/evm/typechain-types/Mailer.d.ts +81 -11
- package/dist/evm/typechain-types/Mailer.d.ts.map +1 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.d.ts +93 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.js +119 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.js.map +1 -1
- package/dist/solana/solana/index.d.ts +1 -1
- package/dist/solana/solana/index.d.ts.map +1 -1
- package/dist/solana/solana/index.js +3 -1
- package/dist/solana/solana/index.js.map +1 -1
- package/dist/solana/solana/mailer-client.d.ts +86 -20
- package/dist/solana/solana/mailer-client.d.ts.map +1 -1
- package/dist/solana/solana/mailer-client.js +290 -58
- package/dist/solana/solana/mailer-client.js.map +1 -1
- package/dist/unified/src/evm/index.d.ts +1 -1
- package/dist/unified/src/evm/index.d.ts.map +1 -1
- package/dist/unified/src/evm/index.js +1 -1
- package/dist/unified/src/evm/index.js.map +1 -1
- package/dist/unified/src/evm/mailer-client.d.ts +936 -180
- package/dist/unified/src/evm/mailer-client.d.ts.map +1 -1
- package/dist/unified/src/evm/mailer-client.js +451 -249
- package/dist/unified/src/evm/mailer-client.js.map +1 -1
- package/dist/unified/src/solana/index.d.ts +1 -1
- package/dist/unified/src/solana/index.d.ts.map +1 -1
- package/dist/unified/src/solana/index.js +3 -1
- package/dist/unified/src/solana/index.js.map +1 -1
- package/dist/unified/src/solana/mailer-client.d.ts +86 -20
- package/dist/unified/src/solana/mailer-client.d.ts.map +1 -1
- package/dist/unified/src/solana/mailer-client.js +290 -58
- package/dist/unified/src/solana/mailer-client.js.map +1 -1
- package/dist/unified/src/unified/onchain-mailer-client.d.ts +25 -0
- package/dist/unified/src/unified/onchain-mailer-client.d.ts.map +1 -1
- package/dist/unified/src/unified/onchain-mailer-client.js +147 -4
- package/dist/unified/src/unified/onchain-mailer-client.js.map +1 -1
- package/dist/unified/typechain-types/Mailer.d.ts +81 -11
- package/dist/unified/typechain-types/Mailer.d.ts.map +1 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.d.ts +93 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.js +119 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.js.map +1 -1
- package/dist/unified-esm/src/evm/index.d.ts +1 -1
- package/dist/unified-esm/src/evm/index.d.ts.map +1 -1
- package/dist/unified-esm/src/evm/index.js +1 -1
- package/dist/unified-esm/src/evm/index.js.map +1 -1
- package/dist/unified-esm/src/evm/mailer-client.d.ts +936 -180
- package/dist/unified-esm/src/evm/mailer-client.d.ts.map +1 -1
- package/dist/unified-esm/src/evm/mailer-client.js +453 -251
- package/dist/unified-esm/src/evm/mailer-client.js.map +1 -1
- package/dist/unified-esm/src/solana/index.d.ts +1 -1
- package/dist/unified-esm/src/solana/index.d.ts.map +1 -1
- package/dist/unified-esm/src/solana/index.js +1 -1
- package/dist/unified-esm/src/solana/index.js.map +1 -1
- package/dist/unified-esm/src/solana/mailer-client.d.ts +86 -20
- package/dist/unified-esm/src/solana/mailer-client.d.ts.map +1 -1
- package/dist/unified-esm/src/solana/mailer-client.js +291 -59
- package/dist/unified-esm/src/solana/mailer-client.js.map +1 -1
- package/dist/unified-esm/src/unified/onchain-mailer-client.d.ts +25 -0
- package/dist/unified-esm/src/unified/onchain-mailer-client.d.ts.map +1 -1
- package/dist/unified-esm/src/unified/onchain-mailer-client.js +147 -4
- package/dist/unified-esm/src/unified/onchain-mailer-client.js.map +1 -1
- package/dist/unified-esm/typechain-types/Mailer.d.ts +81 -11
- package/dist/unified-esm/typechain-types/Mailer.d.ts.map +1 -1
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.d.ts +93 -1
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.js +119 -1
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.js.map +1 -1
- package/package.json +1 -1
- package/typechain-types/Mailer.ts +137 -9
- package/typechain-types/factories/Mailer__factory.ts +119 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PublicKey, Transaction, TransactionInstruction, SystemProgram, } from '@solana/web3.js';
|
|
1
|
+
import { PublicKey, Transaction, TransactionInstruction, SystemProgram, ComputeBudgetProgram, } from '@solana/web3.js';
|
|
2
2
|
import { TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, createAssociatedTokenAccountInstruction, } from '@solana/spl-token';
|
|
3
3
|
/**
|
|
4
4
|
* Native Solana Program instruction data structures
|
|
@@ -32,6 +32,23 @@ function encodeSend(to, subject, body, revenueShareToReceiver, resolveSenderToNa
|
|
|
32
32
|
data.writeUInt8(resolveSenderToName ? 1 : 0, offset);
|
|
33
33
|
return data;
|
|
34
34
|
}
|
|
35
|
+
function encodeSendPrepared(to, mailId, revenueShareToReceiver, resolveSenderToName = false) {
|
|
36
|
+
const mailIdBytes = Buffer.from(mailId, 'utf8');
|
|
37
|
+
const data = Buffer.alloc(1 + 32 + 4 + mailIdBytes.length + 1 + 1);
|
|
38
|
+
let offset = 0;
|
|
39
|
+
data.writeUInt8(InstructionType.SendPrepared, offset);
|
|
40
|
+
offset += 1;
|
|
41
|
+
to.toBuffer().copy(data, offset);
|
|
42
|
+
offset += 32;
|
|
43
|
+
data.writeUInt32LE(mailIdBytes.length, offset);
|
|
44
|
+
offset += 4;
|
|
45
|
+
mailIdBytes.copy(data, offset);
|
|
46
|
+
offset += mailIdBytes.length;
|
|
47
|
+
data.writeUInt8(revenueShareToReceiver ? 1 : 0, offset);
|
|
48
|
+
offset += 1;
|
|
49
|
+
data.writeUInt8(resolveSenderToName ? 1 : 0, offset);
|
|
50
|
+
return data;
|
|
51
|
+
}
|
|
35
52
|
function encodeSendToEmail(toEmail, subject, body) {
|
|
36
53
|
const emailBytes = Buffer.from(toEmail, 'utf8');
|
|
37
54
|
const subjectBytes = Buffer.from(subject, 'utf8');
|
|
@@ -69,6 +86,23 @@ function encodeSendPreparedToEmail(toEmail, mailId) {
|
|
|
69
86
|
mailIdBytes.copy(data, offset);
|
|
70
87
|
return data;
|
|
71
88
|
}
|
|
89
|
+
function encodeSendThroughWebhook(to, webhookId, revenueShareToReceiver, resolveSenderToName = false) {
|
|
90
|
+
const webhookBytes = Buffer.from(webhookId, 'utf8');
|
|
91
|
+
const data = Buffer.alloc(1 + 32 + 4 + webhookBytes.length + 1 + 1);
|
|
92
|
+
let offset = 0;
|
|
93
|
+
data.writeUInt8(InstructionType.SendThroughWebhook, offset);
|
|
94
|
+
offset += 1;
|
|
95
|
+
to.toBuffer().copy(data, offset);
|
|
96
|
+
offset += 32;
|
|
97
|
+
data.writeUInt32LE(webhookBytes.length, offset);
|
|
98
|
+
offset += 4;
|
|
99
|
+
webhookBytes.copy(data, offset);
|
|
100
|
+
offset += webhookBytes.length;
|
|
101
|
+
data.writeUInt8(revenueShareToReceiver ? 1 : 0, offset);
|
|
102
|
+
offset += 1;
|
|
103
|
+
data.writeUInt8(resolveSenderToName ? 1 : 0, offset);
|
|
104
|
+
return data;
|
|
105
|
+
}
|
|
72
106
|
function encodeSimpleInstruction(instructionType) {
|
|
73
107
|
const data = Buffer.alloc(1);
|
|
74
108
|
data.writeUInt8(instructionType, 0);
|
|
@@ -86,6 +120,19 @@ function encodeSetDelegationFee(newFee) {
|
|
|
86
120
|
data.writeBigUInt64LE(newFee, 1);
|
|
87
121
|
return data;
|
|
88
122
|
}
|
|
123
|
+
function encodeSetCustomFeePercentage(account, percentage) {
|
|
124
|
+
const data = Buffer.alloc(1 + 32 + 1);
|
|
125
|
+
data.writeUInt8(InstructionType.SetCustomFeePercentage, 0);
|
|
126
|
+
account.toBuffer().copy(data, 1);
|
|
127
|
+
data.writeUInt8(percentage, 33);
|
|
128
|
+
return data;
|
|
129
|
+
}
|
|
130
|
+
function encodeClearCustomFeePercentage(account) {
|
|
131
|
+
const data = Buffer.alloc(1 + 32);
|
|
132
|
+
data.writeUInt8(InstructionType.ClearCustomFeePercentage, 0);
|
|
133
|
+
account.toBuffer().copy(data, 1);
|
|
134
|
+
return data;
|
|
135
|
+
}
|
|
89
136
|
function encodeDelegateTo(delegate) {
|
|
90
137
|
if (!delegate) {
|
|
91
138
|
// Clear delegation - just send the instruction type and a null option
|
|
@@ -169,26 +216,40 @@ function parseDelegation(data) {
|
|
|
169
216
|
bump,
|
|
170
217
|
};
|
|
171
218
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
219
|
+
function parseFeeDiscount(data) {
|
|
220
|
+
let offset = 0;
|
|
221
|
+
const account = new PublicKey(data.slice(offset, offset + 32));
|
|
222
|
+
offset += 32;
|
|
223
|
+
const discount = data.readUInt8(offset);
|
|
224
|
+
offset += 1;
|
|
225
|
+
const bump = data.readUInt8(offset);
|
|
226
|
+
return {
|
|
227
|
+
account,
|
|
228
|
+
discount,
|
|
229
|
+
bump,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
175
232
|
var InstructionType;
|
|
176
233
|
(function (InstructionType) {
|
|
177
234
|
InstructionType[InstructionType["Initialize"] = 0] = "Initialize";
|
|
178
235
|
InstructionType[InstructionType["Send"] = 1] = "Send";
|
|
179
|
-
InstructionType[InstructionType["
|
|
180
|
-
InstructionType[InstructionType["
|
|
181
|
-
InstructionType[InstructionType["
|
|
182
|
-
InstructionType[InstructionType["
|
|
183
|
-
InstructionType[InstructionType["
|
|
184
|
-
InstructionType[InstructionType["
|
|
185
|
-
InstructionType[InstructionType["
|
|
186
|
-
InstructionType[InstructionType["
|
|
187
|
-
InstructionType[InstructionType["
|
|
188
|
-
InstructionType[InstructionType["
|
|
189
|
-
InstructionType[InstructionType["
|
|
190
|
-
InstructionType[InstructionType["
|
|
191
|
-
InstructionType[InstructionType["
|
|
236
|
+
InstructionType[InstructionType["SendPrepared"] = 2] = "SendPrepared";
|
|
237
|
+
InstructionType[InstructionType["SendToEmail"] = 3] = "SendToEmail";
|
|
238
|
+
InstructionType[InstructionType["SendPreparedToEmail"] = 4] = "SendPreparedToEmail";
|
|
239
|
+
InstructionType[InstructionType["SendThroughWebhook"] = 5] = "SendThroughWebhook";
|
|
240
|
+
InstructionType[InstructionType["ClaimRecipientShare"] = 6] = "ClaimRecipientShare";
|
|
241
|
+
InstructionType[InstructionType["ClaimOwnerShare"] = 7] = "ClaimOwnerShare";
|
|
242
|
+
InstructionType[InstructionType["SetFee"] = 8] = "SetFee";
|
|
243
|
+
InstructionType[InstructionType["DelegateTo"] = 9] = "DelegateTo";
|
|
244
|
+
InstructionType[InstructionType["RejectDelegation"] = 10] = "RejectDelegation";
|
|
245
|
+
InstructionType[InstructionType["SetDelegationFee"] = 11] = "SetDelegationFee";
|
|
246
|
+
InstructionType[InstructionType["SetCustomFeePercentage"] = 12] = "SetCustomFeePercentage";
|
|
247
|
+
InstructionType[InstructionType["ClearCustomFeePercentage"] = 13] = "ClearCustomFeePercentage";
|
|
248
|
+
InstructionType[InstructionType["Pause"] = 14] = "Pause";
|
|
249
|
+
InstructionType[InstructionType["Unpause"] = 15] = "Unpause";
|
|
250
|
+
InstructionType[InstructionType["DistributeClaimableFunds"] = 16] = "DistributeClaimableFunds";
|
|
251
|
+
InstructionType[InstructionType["ClaimExpiredShares"] = 17] = "ClaimExpiredShares";
|
|
252
|
+
InstructionType[InstructionType["EmergencyUnpause"] = 18] = "EmergencyUnpause";
|
|
192
253
|
})(InstructionType || (InstructionType = {}));
|
|
193
254
|
/**
|
|
194
255
|
* @class MailerClient
|
|
@@ -226,6 +287,7 @@ var InstructionType;
|
|
|
226
287
|
*/
|
|
227
288
|
export class MailerClient {
|
|
228
289
|
constructor(connection, wallet, programId, usdcMint) {
|
|
290
|
+
this.defaultComputeUnitMultiplier = 1.2; // 20% buffer by default
|
|
229
291
|
this.connection = connection;
|
|
230
292
|
this.wallet = wallet;
|
|
231
293
|
this.programId = programId;
|
|
@@ -235,10 +297,69 @@ export class MailerClient {
|
|
|
235
297
|
this.mailerStatePda = mailerPda;
|
|
236
298
|
this.mailerBump = bump;
|
|
237
299
|
}
|
|
300
|
+
/**
|
|
301
|
+
* Optimize compute units for a transaction
|
|
302
|
+
* @param transaction Transaction to optimize
|
|
303
|
+
* @param options Compute unit options
|
|
304
|
+
* @returns Optimized transaction with compute budget instructions
|
|
305
|
+
*/
|
|
306
|
+
async optimizeComputeUnits(transaction, options) {
|
|
307
|
+
// Skip if explicitly disabled
|
|
308
|
+
if (options?.skipComputeUnits) {
|
|
309
|
+
return { transaction };
|
|
310
|
+
}
|
|
311
|
+
let simulatedUnits;
|
|
312
|
+
let computeUnitLimit = options?.computeUnitLimit;
|
|
313
|
+
// Auto-optimize by simulating transaction
|
|
314
|
+
if (options?.autoOptimize && !computeUnitLimit) {
|
|
315
|
+
try {
|
|
316
|
+
// Set a high limit for simulation
|
|
317
|
+
const simTransaction = new Transaction().add(...transaction.instructions);
|
|
318
|
+
simTransaction.add(ComputeBudgetProgram.setComputeUnitLimit({
|
|
319
|
+
units: 1400000, // Max for simulation
|
|
320
|
+
}));
|
|
321
|
+
simTransaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
|
|
322
|
+
simTransaction.feePayer = this.wallet.publicKey;
|
|
323
|
+
const simulation = await this.connection.simulateTransaction(simTransaction);
|
|
324
|
+
if (simulation.value.err === null && simulation.value.unitsConsumed) {
|
|
325
|
+
simulatedUnits = simulation.value.unitsConsumed;
|
|
326
|
+
const multiplier = options.computeUnitMultiplier ?? this.defaultComputeUnitMultiplier;
|
|
327
|
+
computeUnitLimit = Math.min(Math.ceil(simulatedUnits * multiplier), 1400000 // Max compute units
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
console.warn('Failed to simulate transaction for compute unit optimization:', error);
|
|
333
|
+
// Fall back to default or specified limit
|
|
334
|
+
computeUnitLimit = computeUnitLimit ?? 200000;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// Create new transaction with compute budget instructions prepended
|
|
338
|
+
const optimizedTx = new Transaction();
|
|
339
|
+
// Add compute unit limit if specified or auto-optimized
|
|
340
|
+
if (computeUnitLimit) {
|
|
341
|
+
optimizedTx.add(ComputeBudgetProgram.setComputeUnitLimit({
|
|
342
|
+
units: computeUnitLimit,
|
|
343
|
+
}));
|
|
344
|
+
}
|
|
345
|
+
// Add priority fee if specified
|
|
346
|
+
if (options?.computeUnitPrice) {
|
|
347
|
+
optimizedTx.add(ComputeBudgetProgram.setComputeUnitPrice({
|
|
348
|
+
microLamports: options.computeUnitPrice,
|
|
349
|
+
}));
|
|
350
|
+
}
|
|
351
|
+
// Add original instructions
|
|
352
|
+
optimizedTx.add(...transaction.instructions);
|
|
353
|
+
return {
|
|
354
|
+
transaction: optimizedTx,
|
|
355
|
+
simulatedUnits,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
238
358
|
/**
|
|
239
359
|
* Initialize the mailer program (owner only)
|
|
360
|
+
* @param computeOptions Compute unit optimization options
|
|
240
361
|
*/
|
|
241
|
-
async initialize() {
|
|
362
|
+
async initialize(computeOptions) {
|
|
242
363
|
const instruction = new TransactionInstruction({
|
|
243
364
|
keys: [
|
|
244
365
|
{ pubkey: this.wallet.publicKey, isSigner: true, isWritable: false },
|
|
@@ -249,7 +370,7 @@ export class MailerClient {
|
|
|
249
370
|
data: encodeInitialize(this.usdcMint),
|
|
250
371
|
});
|
|
251
372
|
const transaction = new Transaction().add(instruction);
|
|
252
|
-
return await this.sendTransaction(transaction);
|
|
373
|
+
return await this.sendTransaction(transaction, undefined, computeOptions);
|
|
253
374
|
}
|
|
254
375
|
/**
|
|
255
376
|
* Send a message with optional revenue sharing
|
|
@@ -258,9 +379,10 @@ export class MailerClient {
|
|
|
258
379
|
* @param body Message body
|
|
259
380
|
* @param revenueShareToReceiver If true, recipient gets 90% revenue share; if false, no revenue share
|
|
260
381
|
* @param resolveSenderToName If true, resolve sender address to name via off-chain service
|
|
261
|
-
* @
|
|
382
|
+
* @param computeOptions Compute unit optimization options
|
|
383
|
+
* @returns Transaction result with signature and compute details
|
|
262
384
|
*/
|
|
263
|
-
async send(to, subject, body, revenueShareToReceiver = false, resolveSenderToName = false) {
|
|
385
|
+
async send(to, subject, body, revenueShareToReceiver = false, resolveSenderToName = false, computeOptions) {
|
|
264
386
|
const recipientKey = typeof to === 'string' ? new PublicKey(to) : to;
|
|
265
387
|
// Derive recipient claim PDA
|
|
266
388
|
const [recipientClaimPda] = PublicKey.findProgramAddressSync([Buffer.from('claim'), recipientKey.toBuffer()], this.programId);
|
|
@@ -290,13 +412,13 @@ export class MailerClient {
|
|
|
290
412
|
});
|
|
291
413
|
instructions.push(sendInstruction);
|
|
292
414
|
const transaction = new Transaction().add(...instructions);
|
|
293
|
-
return await this.sendTransaction(transaction);
|
|
415
|
+
return await this.sendTransaction(transaction, undefined, computeOptions);
|
|
294
416
|
}
|
|
295
417
|
/**
|
|
296
418
|
* Claim recipient share of revenue
|
|
297
|
-
* @returns Transaction
|
|
419
|
+
* @returns Transaction result
|
|
298
420
|
*/
|
|
299
|
-
async claimRecipientShare() {
|
|
421
|
+
async claimRecipientShare(computeOptions) {
|
|
300
422
|
const [recipientClaimPda] = PublicKey.findProgramAddressSync([Buffer.from('claim'), this.wallet.publicKey.toBuffer()], this.programId);
|
|
301
423
|
const recipientTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.wallet.publicKey);
|
|
302
424
|
const mailerTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.mailerStatePda, true);
|
|
@@ -313,13 +435,13 @@ export class MailerClient {
|
|
|
313
435
|
data: encodeSimpleInstruction(InstructionType.ClaimRecipientShare),
|
|
314
436
|
});
|
|
315
437
|
const transaction = new Transaction().add(instruction);
|
|
316
|
-
return await this.sendTransaction(transaction);
|
|
438
|
+
return await this.sendTransaction(transaction, undefined, computeOptions);
|
|
317
439
|
}
|
|
318
440
|
/**
|
|
319
441
|
* Claim owner share of fees (owner only)
|
|
320
|
-
* @returns Transaction
|
|
442
|
+
* @returns Transaction result
|
|
321
443
|
*/
|
|
322
|
-
async claimOwnerShare() {
|
|
444
|
+
async claimOwnerShare(computeOptions) {
|
|
323
445
|
const ownerTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.wallet.publicKey);
|
|
324
446
|
const mailerTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.mailerStatePda, true);
|
|
325
447
|
const instruction = new TransactionInstruction({
|
|
@@ -334,7 +456,7 @@ export class MailerClient {
|
|
|
334
456
|
data: encodeSimpleInstruction(InstructionType.ClaimOwnerShare),
|
|
335
457
|
});
|
|
336
458
|
const transaction = new Transaction().add(instruction);
|
|
337
|
-
return await this.sendTransaction(transaction);
|
|
459
|
+
return await this.sendTransaction(transaction, undefined, computeOptions);
|
|
338
460
|
}
|
|
339
461
|
/**
|
|
340
462
|
* Claim expired recipient shares and move them under owner control
|
|
@@ -342,7 +464,7 @@ export class MailerClient {
|
|
|
342
464
|
* @param options Transaction confirm options
|
|
343
465
|
* @returns Transaction signature
|
|
344
466
|
*/
|
|
345
|
-
async claimExpiredShares(recipient, options) {
|
|
467
|
+
async claimExpiredShares(recipient, options, computeOptions) {
|
|
346
468
|
const recipientKey = typeof recipient === 'string' ? new PublicKey(recipient) : recipient;
|
|
347
469
|
const [recipientClaimPda] = PublicKey.findProgramAddressSync([Buffer.from('claim'), recipientKey.toBuffer()], this.programId);
|
|
348
470
|
const instruction = new TransactionInstruction({
|
|
@@ -355,14 +477,14 @@ export class MailerClient {
|
|
|
355
477
|
data: encodeClaimExpiredShares(recipientKey),
|
|
356
478
|
});
|
|
357
479
|
const transaction = new Transaction().add(instruction);
|
|
358
|
-
return await this.sendTransaction(transaction, options);
|
|
480
|
+
return await this.sendTransaction(transaction, options, computeOptions);
|
|
359
481
|
}
|
|
360
482
|
/**
|
|
361
483
|
* Delegate message handling to another address
|
|
362
484
|
* @param delegate Address to delegate to, or null to clear delegation
|
|
363
485
|
* @returns Transaction signature
|
|
364
486
|
*/
|
|
365
|
-
async delegateTo(delegate) {
|
|
487
|
+
async delegateTo(delegate, computeOptions) {
|
|
366
488
|
const delegateKey = delegate
|
|
367
489
|
? typeof delegate === 'string'
|
|
368
490
|
? new PublicKey(delegate)
|
|
@@ -385,14 +507,14 @@ export class MailerClient {
|
|
|
385
507
|
data: encodeDelegateTo(delegateKey),
|
|
386
508
|
});
|
|
387
509
|
const transaction = new Transaction().add(instruction);
|
|
388
|
-
return await this.sendTransaction(transaction);
|
|
510
|
+
return await this.sendTransaction(transaction, undefined, computeOptions);
|
|
389
511
|
}
|
|
390
512
|
/**
|
|
391
513
|
* Reject a delegation made to you
|
|
392
514
|
* @param delegator Address that delegated to you
|
|
393
515
|
* @returns Transaction signature
|
|
394
516
|
*/
|
|
395
|
-
async rejectDelegation(delegator) {
|
|
517
|
+
async rejectDelegation(delegator, computeOptions) {
|
|
396
518
|
const delegatorKey = typeof delegator === 'string' ? new PublicKey(delegator) : delegator;
|
|
397
519
|
const [delegationPda] = PublicKey.findProgramAddressSync([Buffer.from('delegation'), delegatorKey.toBuffer()], this.programId);
|
|
398
520
|
const instruction = new TransactionInstruction({
|
|
@@ -405,14 +527,15 @@ export class MailerClient {
|
|
|
405
527
|
data: encodeSimpleInstruction(InstructionType.RejectDelegation),
|
|
406
528
|
});
|
|
407
529
|
const transaction = new Transaction().add(instruction);
|
|
408
|
-
return await this.sendTransaction(transaction);
|
|
530
|
+
return await this.sendTransaction(transaction, undefined, computeOptions);
|
|
409
531
|
}
|
|
410
532
|
/**
|
|
411
533
|
* Set the send fee (owner only)
|
|
412
534
|
* @param newFee New fee in USDC micro-units (6 decimals)
|
|
413
|
-
* @
|
|
535
|
+
* @param computeOptions Compute unit optimization options
|
|
536
|
+
* @returns Transaction result
|
|
414
537
|
*/
|
|
415
|
-
async setFee(newFee) {
|
|
538
|
+
async setFee(newFee, computeOptions) {
|
|
416
539
|
const instruction = new TransactionInstruction({
|
|
417
540
|
keys: [
|
|
418
541
|
{ pubkey: this.wallet.publicKey, isSigner: true, isWritable: false },
|
|
@@ -422,14 +545,14 @@ export class MailerClient {
|
|
|
422
545
|
data: encodeSetFee(typeof newFee === 'bigint' ? newFee : BigInt(newFee)),
|
|
423
546
|
});
|
|
424
547
|
const transaction = new Transaction().add(instruction);
|
|
425
|
-
return await this.sendTransaction(transaction);
|
|
548
|
+
return await this.sendTransaction(transaction, undefined, computeOptions);
|
|
426
549
|
}
|
|
427
550
|
/**
|
|
428
551
|
* Set the delegation fee (owner only)
|
|
429
552
|
* @param newFee New delegation fee in USDC micro-units (6 decimals)
|
|
430
553
|
* @returns Transaction signature
|
|
431
554
|
*/
|
|
432
|
-
async setDelegationFee(newFee) {
|
|
555
|
+
async setDelegationFee(newFee, computeOptions) {
|
|
433
556
|
const instruction = new TransactionInstruction({
|
|
434
557
|
keys: [
|
|
435
558
|
{ pubkey: this.wallet.publicKey, isSigner: true, isWritable: false },
|
|
@@ -439,7 +562,59 @@ export class MailerClient {
|
|
|
439
562
|
data: encodeSetDelegationFee(typeof newFee === 'bigint' ? newFee : BigInt(newFee)),
|
|
440
563
|
});
|
|
441
564
|
const transaction = new Transaction().add(instruction);
|
|
442
|
-
return await this.sendTransaction(transaction);
|
|
565
|
+
return await this.sendTransaction(transaction, undefined, computeOptions);
|
|
566
|
+
}
|
|
567
|
+
async setCustomFeePercentage(account, percentage, payer, computeOptions) {
|
|
568
|
+
const normalizedPercentage = Math.trunc(percentage);
|
|
569
|
+
if (normalizedPercentage < 0 || normalizedPercentage > 100) {
|
|
570
|
+
throw new Error('Percentage must be between 0 and 100');
|
|
571
|
+
}
|
|
572
|
+
const accountKey = typeof account === 'string' ? new PublicKey(account) : account;
|
|
573
|
+
const payerKey = payer
|
|
574
|
+
? typeof payer === 'string'
|
|
575
|
+
? new PublicKey(payer)
|
|
576
|
+
: payer
|
|
577
|
+
: this.wallet.publicKey;
|
|
578
|
+
const [discountPda] = PublicKey.findProgramAddressSync([Buffer.from('discount'), accountKey.toBuffer()], this.programId);
|
|
579
|
+
const instruction = new TransactionInstruction({
|
|
580
|
+
keys: [
|
|
581
|
+
{ pubkey: this.wallet.publicKey, isSigner: true, isWritable: false },
|
|
582
|
+
{ pubkey: this.mailerStatePda, isSigner: false, isWritable: false },
|
|
583
|
+
{ pubkey: discountPda, isSigner: false, isWritable: true },
|
|
584
|
+
{ pubkey: accountKey, isSigner: false, isWritable: false },
|
|
585
|
+
{ pubkey: payerKey, isSigner: true, isWritable: true },
|
|
586
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
587
|
+
],
|
|
588
|
+
programId: this.programId,
|
|
589
|
+
data: encodeSetCustomFeePercentage(accountKey, normalizedPercentage),
|
|
590
|
+
});
|
|
591
|
+
const transaction = new Transaction().add(instruction);
|
|
592
|
+
return this.sendTransaction(transaction, undefined, computeOptions);
|
|
593
|
+
}
|
|
594
|
+
async clearCustomFeePercentage(account, computeOptions) {
|
|
595
|
+
const accountKey = typeof account === 'string' ? new PublicKey(account) : account;
|
|
596
|
+
const [discountPda] = PublicKey.findProgramAddressSync([Buffer.from('discount'), accountKey.toBuffer()], this.programId);
|
|
597
|
+
const instruction = new TransactionInstruction({
|
|
598
|
+
keys: [
|
|
599
|
+
{ pubkey: this.wallet.publicKey, isSigner: true, isWritable: false },
|
|
600
|
+
{ pubkey: this.mailerStatePda, isSigner: false, isWritable: false },
|
|
601
|
+
{ pubkey: discountPda, isSigner: false, isWritable: true },
|
|
602
|
+
],
|
|
603
|
+
programId: this.programId,
|
|
604
|
+
data: encodeClearCustomFeePercentage(accountKey),
|
|
605
|
+
});
|
|
606
|
+
const transaction = new Transaction().add(instruction);
|
|
607
|
+
return this.sendTransaction(transaction, undefined, computeOptions);
|
|
608
|
+
}
|
|
609
|
+
async getCustomFeePercentage(account) {
|
|
610
|
+
const accountKey = typeof account === 'string' ? new PublicKey(account) : account;
|
|
611
|
+
const [discountPda] = PublicKey.findProgramAddressSync([Buffer.from('discount'), accountKey.toBuffer()], this.programId);
|
|
612
|
+
const accountInfo = await this.connection.getAccountInfo(discountPda);
|
|
613
|
+
if (!accountInfo) {
|
|
614
|
+
return 100;
|
|
615
|
+
}
|
|
616
|
+
const discountState = parseFeeDiscount(accountInfo.data);
|
|
617
|
+
return 100 - discountState.discount;
|
|
443
618
|
}
|
|
444
619
|
/**
|
|
445
620
|
* Get current fees from the mailer state
|
|
@@ -527,7 +702,7 @@ export class MailerClient {
|
|
|
527
702
|
* @param options Transaction confirm options
|
|
528
703
|
* @returns Transaction signature
|
|
529
704
|
*/
|
|
530
|
-
async sendToEmail(toEmail, subject, body, options) {
|
|
705
|
+
async sendToEmail(toEmail, subject, body, options, computeOptions) {
|
|
531
706
|
// Get associated token accounts
|
|
532
707
|
const senderTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.wallet.publicKey);
|
|
533
708
|
const mailerTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.mailerStatePda, true);
|
|
@@ -553,7 +728,7 @@ export class MailerClient {
|
|
|
553
728
|
data: instructionData,
|
|
554
729
|
}));
|
|
555
730
|
const transaction = new Transaction().add(...instructions);
|
|
556
|
-
return this.sendTransaction(transaction, options);
|
|
731
|
+
return this.sendTransaction(transaction, options, computeOptions);
|
|
557
732
|
}
|
|
558
733
|
/**
|
|
559
734
|
* Send a prepared message to an email address (no wallet known)
|
|
@@ -563,7 +738,7 @@ export class MailerClient {
|
|
|
563
738
|
* @param options Transaction confirm options
|
|
564
739
|
* @returns Transaction signature
|
|
565
740
|
*/
|
|
566
|
-
async sendPreparedToEmail(toEmail, mailId, options) {
|
|
741
|
+
async sendPreparedToEmail(toEmail, mailId, options, computeOptions) {
|
|
567
742
|
// Get associated token accounts
|
|
568
743
|
const senderTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.wallet.publicKey);
|
|
569
744
|
const mailerTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.mailerStatePda, true);
|
|
@@ -589,7 +764,7 @@ export class MailerClient {
|
|
|
589
764
|
data: instructionData,
|
|
590
765
|
}));
|
|
591
766
|
const transaction = new Transaction().add(...instructions);
|
|
592
|
-
return this.sendTransaction(transaction, options);
|
|
767
|
+
return this.sendTransaction(transaction, options, computeOptions);
|
|
593
768
|
}
|
|
594
769
|
/**
|
|
595
770
|
* Send a prepared message using a mailId (to match EVM behavior)
|
|
@@ -599,16 +774,66 @@ export class MailerClient {
|
|
|
599
774
|
* @param resolveSenderToName If true, resolve sender address to name
|
|
600
775
|
* @returns Transaction signature
|
|
601
776
|
*/
|
|
602
|
-
async sendPrepared(to, mailId, revenueShareToReceiver = false, resolveSenderToName = false) {
|
|
603
|
-
|
|
604
|
-
|
|
777
|
+
async sendPrepared(to, mailId, revenueShareToReceiver = false, resolveSenderToName = false, computeOptions) {
|
|
778
|
+
const recipientKey = typeof to === 'string' ? new PublicKey(to) : to;
|
|
779
|
+
const [recipientClaimPda] = PublicKey.findProgramAddressSync([Buffer.from('claim'), recipientKey.toBuffer()], this.programId);
|
|
780
|
+
const senderTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.wallet.publicKey);
|
|
781
|
+
const mailerTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.mailerStatePda, true);
|
|
782
|
+
const instructions = [];
|
|
783
|
+
const mailerTokenInfo = await this.connection.getAccountInfo(mailerTokenAccount);
|
|
784
|
+
if (!mailerTokenInfo) {
|
|
785
|
+
instructions.push(createAssociatedTokenAccountInstruction(this.wallet.publicKey, mailerTokenAccount, this.mailerStatePda, this.usdcMint));
|
|
786
|
+
}
|
|
787
|
+
const sendInstruction = new TransactionInstruction({
|
|
788
|
+
keys: [
|
|
789
|
+
{ pubkey: this.wallet.publicKey, isSigner: true, isWritable: false },
|
|
790
|
+
{ pubkey: recipientClaimPda, isSigner: false, isWritable: true },
|
|
791
|
+
{ pubkey: this.mailerStatePda, isSigner: false, isWritable: false },
|
|
792
|
+
{ pubkey: senderTokenAccount, isSigner: false, isWritable: true },
|
|
793
|
+
{ pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
|
|
794
|
+
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
795
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
796
|
+
],
|
|
797
|
+
programId: this.programId,
|
|
798
|
+
data: encodeSendPrepared(recipientKey, mailId, revenueShareToReceiver, resolveSenderToName),
|
|
799
|
+
});
|
|
800
|
+
instructions.push(sendInstruction);
|
|
801
|
+
const transaction = new Transaction().add(...instructions);
|
|
802
|
+
return this.sendTransaction(transaction, undefined, computeOptions);
|
|
803
|
+
}
|
|
804
|
+
async sendThroughWebhook(to, webhookId, revenueShareToReceiver = false, resolveSenderToName = false, computeOptions) {
|
|
805
|
+
const recipientKey = typeof to === 'string' ? new PublicKey(to) : to;
|
|
806
|
+
const [recipientClaimPda] = PublicKey.findProgramAddressSync([Buffer.from('claim'), recipientKey.toBuffer()], this.programId);
|
|
807
|
+
const senderTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.wallet.publicKey);
|
|
808
|
+
const mailerTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.mailerStatePda, true);
|
|
809
|
+
const instructions = [];
|
|
810
|
+
const mailerTokenInfo = await this.connection.getAccountInfo(mailerTokenAccount);
|
|
811
|
+
if (!mailerTokenInfo) {
|
|
812
|
+
instructions.push(createAssociatedTokenAccountInstruction(this.wallet.publicKey, mailerTokenAccount, this.mailerStatePda, this.usdcMint));
|
|
813
|
+
}
|
|
814
|
+
const sendInstruction = new TransactionInstruction({
|
|
815
|
+
keys: [
|
|
816
|
+
{ pubkey: this.wallet.publicKey, isSigner: true, isWritable: false },
|
|
817
|
+
{ pubkey: recipientClaimPda, isSigner: false, isWritable: true },
|
|
818
|
+
{ pubkey: this.mailerStatePda, isSigner: false, isWritable: false },
|
|
819
|
+
{ pubkey: senderTokenAccount, isSigner: false, isWritable: true },
|
|
820
|
+
{ pubkey: mailerTokenAccount, isSigner: false, isWritable: true },
|
|
821
|
+
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
822
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
823
|
+
],
|
|
824
|
+
programId: this.programId,
|
|
825
|
+
data: encodeSendThroughWebhook(recipientKey, webhookId, revenueShareToReceiver, resolveSenderToName),
|
|
826
|
+
});
|
|
827
|
+
instructions.push(sendInstruction);
|
|
828
|
+
const transaction = new Transaction().add(...instructions);
|
|
829
|
+
return this.sendTransaction(transaction, undefined, computeOptions);
|
|
605
830
|
}
|
|
606
831
|
/**
|
|
607
832
|
* Pause the contract and distribute owner claimable funds (owner only)
|
|
608
833
|
* @param options Transaction confirm options
|
|
609
834
|
* @returns Transaction signature
|
|
610
835
|
*/
|
|
611
|
-
async pause(options) {
|
|
836
|
+
async pause(options, computeOptions) {
|
|
612
837
|
const ownerTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.wallet.publicKey);
|
|
613
838
|
const mailerTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, this.mailerStatePda, true);
|
|
614
839
|
const instruction = new TransactionInstruction({
|
|
@@ -623,14 +848,14 @@ export class MailerClient {
|
|
|
623
848
|
data: encodeSimpleInstruction(InstructionType.Pause),
|
|
624
849
|
});
|
|
625
850
|
const transaction = new Transaction().add(instruction);
|
|
626
|
-
return await this.sendTransaction(transaction, options);
|
|
851
|
+
return await this.sendTransaction(transaction, options, computeOptions);
|
|
627
852
|
}
|
|
628
853
|
/**
|
|
629
854
|
* Unpause the contract (owner only)
|
|
630
855
|
* @param options Transaction confirm options
|
|
631
856
|
* @returns Transaction signature
|
|
632
857
|
*/
|
|
633
|
-
async unpause(options) {
|
|
858
|
+
async unpause(options, computeOptions) {
|
|
634
859
|
const instruction = new TransactionInstruction({
|
|
635
860
|
keys: [
|
|
636
861
|
{ pubkey: this.wallet.publicKey, isSigner: true, isWritable: false },
|
|
@@ -640,14 +865,14 @@ export class MailerClient {
|
|
|
640
865
|
data: encodeSimpleInstruction(InstructionType.Unpause),
|
|
641
866
|
});
|
|
642
867
|
const transaction = new Transaction().add(instruction);
|
|
643
|
-
return await this.sendTransaction(transaction, options);
|
|
868
|
+
return await this.sendTransaction(transaction, options, computeOptions);
|
|
644
869
|
}
|
|
645
870
|
/**
|
|
646
871
|
* Emergency unpause without fund distribution (owner only)
|
|
647
872
|
* @param options Transaction confirm options
|
|
648
873
|
* @returns Transaction signature
|
|
649
874
|
*/
|
|
650
|
-
async emergencyUnpause(options) {
|
|
875
|
+
async emergencyUnpause(options, computeOptions) {
|
|
651
876
|
const instruction = new TransactionInstruction({
|
|
652
877
|
keys: [
|
|
653
878
|
{ pubkey: this.wallet.publicKey, isSigner: true, isWritable: false },
|
|
@@ -657,7 +882,7 @@ export class MailerClient {
|
|
|
657
882
|
data: encodeSimpleInstruction(InstructionType.EmergencyUnpause),
|
|
658
883
|
});
|
|
659
884
|
const transaction = new Transaction().add(instruction);
|
|
660
|
-
return await this.sendTransaction(transaction, options);
|
|
885
|
+
return await this.sendTransaction(transaction, options, computeOptions);
|
|
661
886
|
}
|
|
662
887
|
/**
|
|
663
888
|
* Distribute claimable funds to a recipient when contract is paused
|
|
@@ -665,7 +890,7 @@ export class MailerClient {
|
|
|
665
890
|
* @param options Transaction confirm options
|
|
666
891
|
* @returns Transaction signature
|
|
667
892
|
*/
|
|
668
|
-
async distributeClaimableFunds(recipient, options) {
|
|
893
|
+
async distributeClaimableFunds(recipient, options, computeOptions) {
|
|
669
894
|
const recipientKey = typeof recipient === 'string' ? new PublicKey(recipient) : recipient;
|
|
670
895
|
const [recipientClaimPda] = PublicKey.findProgramAddressSync([Buffer.from('claim'), recipientKey.toBuffer()], this.programId);
|
|
671
896
|
const recipientTokenAccount = getAssociatedTokenAddressSync(this.usdcMint, recipientKey);
|
|
@@ -687,7 +912,7 @@ export class MailerClient {
|
|
|
687
912
|
data,
|
|
688
913
|
});
|
|
689
914
|
const transaction = new Transaction().add(instruction);
|
|
690
|
-
return await this.sendTransaction(transaction, options);
|
|
915
|
+
return await this.sendTransaction(transaction, options, computeOptions);
|
|
691
916
|
}
|
|
692
917
|
/**
|
|
693
918
|
* Get the current send fee
|
|
@@ -716,17 +941,24 @@ export class MailerClient {
|
|
|
716
941
|
* @param options Confirm options
|
|
717
942
|
* @returns Transaction signature
|
|
718
943
|
*/
|
|
719
|
-
async sendTransaction(transaction, options) {
|
|
944
|
+
async sendTransaction(transaction, options, computeOptions) {
|
|
945
|
+
// Optimize compute units if requested
|
|
946
|
+
const { transaction: optimizedTx, simulatedUnits } = await this.optimizeComputeUnits(transaction, computeOptions);
|
|
720
947
|
// Get recent blockhash
|
|
721
948
|
const { blockhash } = await this.connection.getLatestBlockhash();
|
|
722
|
-
|
|
723
|
-
|
|
949
|
+
optimizedTx.recentBlockhash = blockhash;
|
|
950
|
+
optimizedTx.feePayer = this.wallet.publicKey;
|
|
724
951
|
// Sign transaction
|
|
725
|
-
const signedTx = await this.wallet.signTransaction(
|
|
952
|
+
const signedTx = await this.wallet.signTransaction(optimizedTx);
|
|
726
953
|
// Send and confirm
|
|
727
954
|
const signature = await this.connection.sendRawTransaction(signedTx.serialize());
|
|
728
955
|
await this.connection.confirmTransaction(signature, options?.commitment || 'confirmed');
|
|
729
|
-
return
|
|
956
|
+
return {
|
|
957
|
+
signature,
|
|
958
|
+
simulatedUnits,
|
|
959
|
+
computeUnitLimit: computeOptions?.computeUnitLimit,
|
|
960
|
+
computeUnitPrice: computeOptions?.computeUnitPrice,
|
|
961
|
+
};
|
|
730
962
|
}
|
|
731
963
|
/**
|
|
732
964
|
* Create a simple wallet from a keypair for testing
|