@sudobility/contracts 0.15.1 → 1.10.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/README.md +2 -3
- package/artifacts/contracts/Mailer.sol/Mailer.d.ts +2 -185
- package/artifacts/contracts/Mailer.sol/Mailer.dbg.json +1 -1
- package/artifacts/contracts/Mailer.sol/Mailer.json +2 -185
- 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 +4 -4
- package/dist/evm/src/evm/index.js.map +1 -1
- package/dist/evm/src/evm/mailer-client.d.ts +210 -0
- package/dist/evm/src/evm/mailer-client.d.ts.map +1 -0
- package/dist/evm/src/evm/mailer-client.js +417 -0
- package/dist/evm/src/evm/mailer-client.js.map +1 -0
- package/dist/evm/typechain-types/Mailer.d.ts +10 -128
- package/dist/evm/typechain-types/Mailer.d.ts.map +1 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.d.ts +1 -145
- package/dist/evm/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.js +1 -184
- 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 +1 -4
- package/dist/solana/solana/index.js.map +1 -1
- package/dist/solana/solana/mailer-client.d.ts +209 -0
- package/dist/solana/solana/mailer-client.d.ts.map +1 -0
- package/dist/solana/solana/mailer-client.js +728 -0
- package/dist/solana/solana/mailer-client.js.map +1 -0
- package/dist/solana/solana/types.d.ts +2 -3
- package/dist/solana/solana/types.d.ts.map +1 -1
- package/dist/solana/solana/types.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 +4 -4
- package/dist/unified/src/evm/index.js.map +1 -1
- package/dist/unified/src/evm/mailer-client.d.ts +210 -0
- package/dist/unified/src/evm/mailer-client.d.ts.map +1 -0
- package/dist/unified/src/evm/mailer-client.js +417 -0
- package/dist/unified/src/evm/mailer-client.js.map +1 -0
- package/dist/unified/src/react/context/MailerProvider.d.ts +20 -26
- package/dist/unified/src/react/context/MailerProvider.d.ts.map +1 -1
- package/dist/unified/src/react/context/MailerProvider.js +26 -26
- package/dist/unified/src/react/context/MailerProvider.js.map +1 -1
- package/dist/unified/src/react/hooks/useMailerMutations.d.ts +192 -225
- package/dist/unified/src/react/hooks/useMailerMutations.d.ts.map +1 -1
- package/dist/unified/src/react/hooks/useMailerMutations.js +266 -263
- package/dist/unified/src/react/hooks/useMailerMutations.js.map +1 -1
- package/dist/unified/src/react/hooks/useMailerQueries.d.ts +63 -117
- package/dist/unified/src/react/hooks/useMailerQueries.d.ts.map +1 -1
- package/dist/unified/src/react/hooks/useMailerQueries.js +104 -239
- package/dist/unified/src/react/hooks/useMailerQueries.js.map +1 -1
- package/dist/unified/src/react/index.d.ts +3 -5
- package/dist/unified/src/react/index.d.ts.map +1 -1
- package/dist/unified/src/react/index.js +26 -41
- package/dist/unified/src/react/index.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 +1 -4
- package/dist/unified/src/solana/index.js.map +1 -1
- package/dist/unified/src/solana/mailer-client.d.ts +209 -0
- package/dist/unified/src/solana/mailer-client.d.ts.map +1 -0
- package/dist/unified/src/solana/mailer-client.js +728 -0
- package/dist/unified/src/solana/mailer-client.js.map +1 -0
- package/dist/unified/src/solana/types.d.ts +2 -3
- package/dist/unified/src/solana/types.d.ts.map +1 -1
- package/dist/unified/src/solana/types.js.map +1 -1
- package/dist/unified/src/unified/index.d.ts +1 -1
- package/dist/unified/src/unified/index.d.ts.map +1 -1
- package/dist/unified/src/unified/onchain-mailer-client.d.ts +247 -192
- package/dist/unified/src/unified/onchain-mailer-client.d.ts.map +1 -1
- package/dist/unified/src/unified/onchain-mailer-client.js +1462 -551
- package/dist/unified/src/unified/onchain-mailer-client.js.map +1 -1
- package/dist/unified/src/unified/types.d.ts +6 -23
- package/dist/unified/src/unified/types.d.ts.map +1 -1
- package/dist/unified/src/utils/chain-config.d.ts +2 -4
- package/dist/unified/src/utils/chain-config.d.ts.map +1 -1
- package/dist/unified/src/utils/chain-config.js +36 -46
- package/dist/unified/src/utils/chain-config.js.map +1 -1
- package/dist/unified/typechain-types/Mailer.d.ts +10 -128
- package/dist/unified/typechain-types/Mailer.d.ts.map +1 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.d.ts +1 -145
- package/dist/unified/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.js +1 -184
- 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 +2 -2
- package/dist/unified-esm/src/evm/index.js.map +1 -1
- package/dist/unified-esm/src/evm/mailer-client.d.ts +210 -0
- package/dist/unified-esm/src/evm/mailer-client.d.ts.map +1 -0
- package/dist/unified-esm/src/evm/mailer-client.js +413 -0
- package/dist/unified-esm/src/evm/mailer-client.js.map +1 -0
- package/dist/unified-esm/src/react/context/MailerProvider.d.ts +20 -26
- package/dist/unified-esm/src/react/context/MailerProvider.d.ts.map +1 -1
- package/dist/unified-esm/src/react/context/MailerProvider.js +26 -25
- package/dist/unified-esm/src/react/context/MailerProvider.js.map +1 -1
- package/dist/unified-esm/src/react/hooks/useMailerMutations.d.ts +192 -225
- package/dist/unified-esm/src/react/hooks/useMailerMutations.d.ts.map +1 -1
- package/dist/unified-esm/src/react/hooks/useMailerMutations.js +262 -254
- package/dist/unified-esm/src/react/hooks/useMailerMutations.js.map +1 -1
- package/dist/unified-esm/src/react/hooks/useMailerQueries.d.ts +63 -117
- package/dist/unified-esm/src/react/hooks/useMailerQueries.d.ts.map +1 -1
- package/dist/unified-esm/src/react/hooks/useMailerQueries.js +102 -232
- package/dist/unified-esm/src/react/hooks/useMailerQueries.js.map +1 -1
- package/dist/unified-esm/src/react/index.d.ts +3 -5
- package/dist/unified-esm/src/react/index.d.ts.map +1 -1
- package/dist/unified-esm/src/react/index.js +5 -9
- package/dist/unified-esm/src/react/index.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 -2
- package/dist/unified-esm/src/solana/index.js.map +1 -1
- package/dist/unified-esm/src/solana/mailer-client.d.ts +209 -0
- package/dist/unified-esm/src/solana/mailer-client.d.ts.map +1 -0
- package/dist/unified-esm/src/solana/mailer-client.js +724 -0
- package/dist/unified-esm/src/solana/mailer-client.js.map +1 -0
- package/dist/unified-esm/src/solana/types.d.ts +2 -3
- package/dist/unified-esm/src/solana/types.d.ts.map +1 -1
- package/dist/unified-esm/src/solana/types.js.map +1 -1
- package/dist/unified-esm/src/unified/index.d.ts +1 -1
- package/dist/unified-esm/src/unified/index.d.ts.map +1 -1
- package/dist/unified-esm/src/unified/onchain-mailer-client.d.ts +247 -192
- package/dist/unified-esm/src/unified/onchain-mailer-client.d.ts.map +1 -1
- package/dist/unified-esm/src/unified/onchain-mailer-client.js +1462 -551
- package/dist/unified-esm/src/unified/onchain-mailer-client.js.map +1 -1
- package/dist/unified-esm/src/unified/types.d.ts +6 -23
- package/dist/unified-esm/src/unified/types.d.ts.map +1 -1
- package/dist/unified-esm/src/utils/chain-config.d.ts +2 -4
- package/dist/unified-esm/src/utils/chain-config.d.ts.map +1 -1
- package/dist/unified-esm/src/utils/chain-config.js +35 -46
- package/dist/unified-esm/src/utils/chain-config.js.map +1 -1
- package/dist/unified-esm/typechain-types/Mailer.d.ts +10 -128
- package/dist/unified-esm/typechain-types/Mailer.d.ts.map +1 -1
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.d.ts +1 -145
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.js +1 -184
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.js.map +1 -1
- package/package.json +10 -17
- package/programs/mailer/src/lib.rs +145 -764
- package/programs/mailer/tests/integration_tests.rs +65 -586
- package/typechain-types/Mailer.ts +8 -215
- package/typechain-types/factories/Mailer__factory.ts +1 -184
- package/dist/evm/src/evm/evm-mailer-client.d.ts +0 -1062
- package/dist/evm/src/evm/evm-mailer-client.d.ts.map +0 -1
- package/dist/evm/src/evm/evm-mailer-client.js +0 -924
- package/dist/evm/src/evm/evm-mailer-client.js.map +0 -1
- package/dist/solana/solana/solana-mailer-client.d.ts +0 -209
- package/dist/solana/solana/solana-mailer-client.d.ts.map +0 -1
- package/dist/solana/solana/solana-mailer-client.js +0 -1004
- package/dist/solana/solana/solana-mailer-client.js.map +0 -1
- package/dist/unified/src/evm/evm-mailer-client.d.ts +0 -1062
- package/dist/unified/src/evm/evm-mailer-client.d.ts.map +0 -1
- package/dist/unified/src/evm/evm-mailer-client.js +0 -924
- package/dist/unified/src/evm/evm-mailer-client.js.map +0 -1
- package/dist/unified/src/solana/solana-mailer-client.d.ts +0 -209
- package/dist/unified/src/solana/solana-mailer-client.d.ts.map +0 -1
- package/dist/unified/src/solana/solana-mailer-client.js +0 -1004
- package/dist/unified/src/solana/solana-mailer-client.js.map +0 -1
- package/dist/unified-esm/src/evm/evm-mailer-client.d.ts +0 -1062
- package/dist/unified-esm/src/evm/evm-mailer-client.d.ts.map +0 -1
- package/dist/unified-esm/src/evm/evm-mailer-client.js +0 -920
- package/dist/unified-esm/src/evm/evm-mailer-client.js.map +0 -1
- package/dist/unified-esm/src/solana/solana-mailer-client.d.ts +0 -209
- package/dist/unified-esm/src/solana/solana-mailer-client.d.ts.map +0 -1
- package/dist/unified-esm/src/solana/solana-mailer-client.js +0 -1000
- package/dist/unified-esm/src/solana/solana-mailer-client.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//! # Native Solana Mailer Program
|
|
2
2
|
//!
|
|
3
|
-
//! A native Solana program for decentralized messaging with delegation management,
|
|
3
|
+
//! A native Solana program for decentralized messaging with delegation management,
|
|
4
4
|
//! USDC fees and revenue sharing - no Anchor dependencies.
|
|
5
5
|
//!
|
|
6
6
|
//! ## Key Features
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
//! - Standard: Sender pays 10% fee only
|
|
26
26
|
//! - Owner gets 10% of all fees
|
|
27
27
|
|
|
28
|
+
|
|
28
29
|
use borsh::{BorshDeserialize, BorshSerialize};
|
|
29
30
|
use solana_program::{
|
|
30
31
|
account_info::{next_account_info, AccountInfo},
|
|
@@ -33,13 +34,11 @@ use solana_program::{
|
|
|
33
34
|
msg,
|
|
34
35
|
program::{invoke, invoke_signed},
|
|
35
36
|
program_error::ProgramError,
|
|
36
|
-
program_pack::Pack,
|
|
37
37
|
pubkey::Pubkey,
|
|
38
38
|
rent::Rent,
|
|
39
39
|
system_instruction,
|
|
40
40
|
sysvar::Sysvar,
|
|
41
41
|
};
|
|
42
|
-
use spl_token::state::Account as TokenAccount;
|
|
43
42
|
use thiserror::Error;
|
|
44
43
|
|
|
45
44
|
// Program ID for the Native Mailer program
|
|
@@ -139,22 +138,6 @@ pub enum MailerInstruction {
|
|
|
139
138
|
resolve_sender_to_name: bool,
|
|
140
139
|
},
|
|
141
140
|
|
|
142
|
-
/// Send prepared message with optional revenue sharing (references off-chain content via mailId)
|
|
143
|
-
/// Accounts:
|
|
144
|
-
/// 0. `[signer]` Sender
|
|
145
|
-
/// 1. `[writable]` Recipient claim account (PDA)
|
|
146
|
-
/// 2. `[]` Mailer state account (PDA)
|
|
147
|
-
/// 3. `[writable]` Sender USDC account
|
|
148
|
-
/// 4. `[writable]` Mailer USDC account
|
|
149
|
-
/// 5. `[]` Token program
|
|
150
|
-
/// 6. `[]` System program
|
|
151
|
-
SendPrepared {
|
|
152
|
-
to: Pubkey,
|
|
153
|
-
mail_id: String,
|
|
154
|
-
revenue_share_to_receiver: bool,
|
|
155
|
-
resolve_sender_to_name: bool,
|
|
156
|
-
},
|
|
157
|
-
|
|
158
141
|
/// Send message to email address (no wallet address known)
|
|
159
142
|
/// Charges only 10% owner fee since recipient wallet is unknown
|
|
160
143
|
/// Accounts:
|
|
@@ -177,22 +160,9 @@ pub enum MailerInstruction {
|
|
|
177
160
|
/// 2. `[writable]` Sender USDC account
|
|
178
161
|
/// 3. `[writable]` Mailer USDC account
|
|
179
162
|
/// 4. `[]` Token program
|
|
180
|
-
SendPreparedToEmail {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
/// Accounts:
|
|
184
|
-
/// 0. `[signer]` Sender
|
|
185
|
-
/// 1. `[writable]` Recipient claim account (PDA)
|
|
186
|
-
/// 2. `[]` Mailer state account (PDA)
|
|
187
|
-
/// 3. `[writable]` Sender USDC account
|
|
188
|
-
/// 4. `[writable]` Mailer USDC account
|
|
189
|
-
/// 5. `[]` Token program
|
|
190
|
-
/// 6. `[]` System program
|
|
191
|
-
SendThroughWebhook {
|
|
192
|
-
to: Pubkey,
|
|
193
|
-
webhook_id: String,
|
|
194
|
-
revenue_share_to_receiver: bool,
|
|
195
|
-
resolve_sender_to_name: bool,
|
|
163
|
+
SendPreparedToEmail {
|
|
164
|
+
to_email: String,
|
|
165
|
+
mail_id: String,
|
|
196
166
|
},
|
|
197
167
|
|
|
198
168
|
/// Claim recipient share
|
|
@@ -235,7 +205,6 @@ pub enum MailerInstruction {
|
|
|
235
205
|
/// Accounts:
|
|
236
206
|
/// 0. `[signer]` Rejector
|
|
237
207
|
/// 1. `[writable]` Delegation account (PDA)
|
|
238
|
-
/// 2. `[]` Mailer state account (PDA)
|
|
239
208
|
RejectDelegation,
|
|
240
209
|
|
|
241
210
|
/// Set delegation fee (owner only)
|
|
@@ -272,13 +241,13 @@ pub enum MailerInstruction {
|
|
|
272
241
|
/// 3. `[writable]` Mailer USDC account
|
|
273
242
|
/// 4. `[]` Token program
|
|
274
243
|
Pause,
|
|
275
|
-
|
|
244
|
+
|
|
276
245
|
/// Unpause the contract (owner only)
|
|
277
246
|
/// Accounts:
|
|
278
247
|
/// 0. `[signer]` Owner
|
|
279
248
|
/// 1. `[writable]` Mailer state account (PDA)
|
|
280
249
|
Unpause,
|
|
281
|
-
|
|
250
|
+
|
|
282
251
|
/// Distribute claimable funds (when paused)
|
|
283
252
|
/// Accounts:
|
|
284
253
|
/// 0. `[signer]` Anyone can call
|
|
@@ -289,13 +258,6 @@ pub enum MailerInstruction {
|
|
|
289
258
|
/// 5. `[]` Token program
|
|
290
259
|
DistributeClaimableFunds { recipient: Pubkey },
|
|
291
260
|
|
|
292
|
-
/// Claim expired recipient shares (owner only)
|
|
293
|
-
/// Accounts:
|
|
294
|
-
/// 0. `[signer]` Owner
|
|
295
|
-
/// 1. `[writable]` Mailer state account (PDA)
|
|
296
|
-
/// 2. `[writable]` Recipient claim account (PDA)
|
|
297
|
-
ClaimExpiredShares { recipient: Pubkey },
|
|
298
|
-
|
|
299
261
|
/// Emergency unpause without fund distribution (owner only)
|
|
300
262
|
/// Accounts:
|
|
301
263
|
/// 0. `[signer]` Owner
|
|
@@ -328,10 +290,6 @@ pub enum MailerError {
|
|
|
328
290
|
InvalidPDA,
|
|
329
291
|
#[error("Invalid account owner")]
|
|
330
292
|
InvalidAccountOwner,
|
|
331
|
-
#[error("Invalid token mint")]
|
|
332
|
-
InvalidMint,
|
|
333
|
-
#[error("Invalid token program")]
|
|
334
|
-
InvalidTokenProgram,
|
|
335
293
|
#[error("Contract is paused")]
|
|
336
294
|
ContractPaused,
|
|
337
295
|
#[error("Contract is not paused")]
|
|
@@ -358,55 +316,15 @@ pub fn process_instruction(
|
|
|
358
316
|
MailerInstruction::Initialize { usdc_mint } => {
|
|
359
317
|
process_initialize(program_id, accounts, usdc_mint)
|
|
360
318
|
}
|
|
361
|
-
MailerInstruction::Send {
|
|
362
|
-
to,
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
} => process_send(
|
|
368
|
-
program_id,
|
|
369
|
-
accounts,
|
|
370
|
-
to,
|
|
371
|
-
subject,
|
|
372
|
-
_body,
|
|
373
|
-
revenue_share_to_receiver,
|
|
374
|
-
resolve_sender_to_name,
|
|
375
|
-
),
|
|
376
|
-
MailerInstruction::SendPrepared {
|
|
377
|
-
to,
|
|
378
|
-
mail_id,
|
|
379
|
-
revenue_share_to_receiver,
|
|
380
|
-
resolve_sender_to_name,
|
|
381
|
-
} => process_send_prepared(
|
|
382
|
-
program_id,
|
|
383
|
-
accounts,
|
|
384
|
-
to,
|
|
385
|
-
mail_id,
|
|
386
|
-
revenue_share_to_receiver,
|
|
387
|
-
resolve_sender_to_name,
|
|
388
|
-
),
|
|
389
|
-
MailerInstruction::SendToEmail {
|
|
390
|
-
to_email,
|
|
391
|
-
subject,
|
|
392
|
-
_body,
|
|
393
|
-
} => process_send_to_email(program_id, accounts, to_email, subject, _body),
|
|
319
|
+
MailerInstruction::Send { to, subject, _body, revenue_share_to_receiver, resolve_sender_to_name } => {
|
|
320
|
+
process_send(program_id, accounts, to, subject, _body, revenue_share_to_receiver, resolve_sender_to_name)
|
|
321
|
+
}
|
|
322
|
+
MailerInstruction::SendToEmail { to_email, subject, _body } => {
|
|
323
|
+
process_send_to_email(program_id, accounts, to_email, subject, _body)
|
|
324
|
+
}
|
|
394
325
|
MailerInstruction::SendPreparedToEmail { to_email, mail_id } => {
|
|
395
326
|
process_send_prepared_to_email(program_id, accounts, to_email, mail_id)
|
|
396
327
|
}
|
|
397
|
-
MailerInstruction::SendThroughWebhook {
|
|
398
|
-
to,
|
|
399
|
-
webhook_id,
|
|
400
|
-
revenue_share_to_receiver,
|
|
401
|
-
resolve_sender_to_name,
|
|
402
|
-
} => process_send_through_webhook(
|
|
403
|
-
program_id,
|
|
404
|
-
accounts,
|
|
405
|
-
to,
|
|
406
|
-
webhook_id,
|
|
407
|
-
revenue_share_to_receiver,
|
|
408
|
-
resolve_sender_to_name,
|
|
409
|
-
),
|
|
410
328
|
MailerInstruction::ClaimRecipientShare => {
|
|
411
329
|
process_claim_recipient_share(program_id, accounts)
|
|
412
330
|
}
|
|
@@ -419,22 +337,24 @@ pub fn process_instruction(
|
|
|
419
337
|
MailerInstruction::SetDelegationFee { new_fee } => {
|
|
420
338
|
process_set_delegation_fee(program_id, accounts, new_fee)
|
|
421
339
|
}
|
|
422
|
-
MailerInstruction::SetCustomFeePercentage {
|
|
423
|
-
account,
|
|
424
|
-
|
|
425
|
-
} => process_set_custom_fee_percentage(program_id, accounts, account, percentage),
|
|
340
|
+
MailerInstruction::SetCustomFeePercentage { account, percentage } => {
|
|
341
|
+
process_set_custom_fee_percentage(program_id, accounts, account, percentage)
|
|
342
|
+
}
|
|
426
343
|
MailerInstruction::ClearCustomFeePercentage { account } => {
|
|
427
344
|
process_clear_custom_fee_percentage(program_id, accounts, account)
|
|
428
345
|
}
|
|
429
|
-
MailerInstruction::Pause =>
|
|
430
|
-
|
|
346
|
+
MailerInstruction::Pause => {
|
|
347
|
+
process_pause(program_id, accounts)
|
|
348
|
+
}
|
|
349
|
+
MailerInstruction::Unpause => {
|
|
350
|
+
process_unpause(program_id, accounts)
|
|
351
|
+
}
|
|
431
352
|
MailerInstruction::DistributeClaimableFunds { recipient } => {
|
|
432
353
|
process_distribute_claimable_funds(program_id, accounts, recipient)
|
|
433
354
|
}
|
|
434
|
-
MailerInstruction::
|
|
435
|
-
|
|
355
|
+
MailerInstruction::EmergencyUnpause => {
|
|
356
|
+
process_emergency_unpause(program_id, accounts)
|
|
436
357
|
}
|
|
437
|
-
MailerInstruction::EmergencyUnpause => process_emergency_unpause(program_id, accounts),
|
|
438
358
|
}
|
|
439
359
|
}
|
|
440
360
|
|
|
@@ -472,11 +392,7 @@ fn process_initialize(
|
|
|
472
392
|
space as u64,
|
|
473
393
|
program_id,
|
|
474
394
|
),
|
|
475
|
-
&[
|
|
476
|
-
owner.clone(),
|
|
477
|
-
mailer_account.clone(),
|
|
478
|
-
system_program.clone(),
|
|
479
|
-
],
|
|
395
|
+
&[owner.clone(), mailer_account.clone(), system_program.clone()],
|
|
480
396
|
&[&[b"mailer", &[bump]]],
|
|
481
397
|
)?;
|
|
482
398
|
|
|
@@ -524,187 +440,26 @@ fn process_send(
|
|
|
524
440
|
}
|
|
525
441
|
|
|
526
442
|
// Load mailer state
|
|
527
|
-
let (mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
528
443
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
529
444
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
530
445
|
drop(mailer_data);
|
|
531
446
|
|
|
532
|
-
assert_token_program(token_program)?;
|
|
533
|
-
assert_token_account(sender_usdc, sender.key, &mailer_state.usdc_mint)?;
|
|
534
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
535
|
-
|
|
536
447
|
// Check if contract is paused
|
|
537
448
|
if mailer_state.paused {
|
|
538
449
|
return Err(MailerError::ContractPaused.into());
|
|
539
450
|
}
|
|
540
451
|
|
|
541
452
|
// Calculate effective fee based on custom discount (if any)
|
|
542
|
-
let effective_fee =
|
|
543
|
-
calculate_fee_with_discount(program_id, sender.key, accounts, mailer_state.send_fee)?;
|
|
453
|
+
let effective_fee = calculate_fee_with_discount(program_id, sender.key, accounts, mailer_state.send_fee)?;
|
|
544
454
|
|
|
545
455
|
if revenue_share_to_receiver {
|
|
546
456
|
// Priority mode: full fee with revenue sharing
|
|
547
457
|
|
|
548
458
|
// Create or load recipient claim account
|
|
549
|
-
let (claim_pda, claim_bump) =
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
if recipient_claim.key != &claim_pda {
|
|
553
|
-
return Err(MailerError::InvalidPDA.into());
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// Create claim account if needed
|
|
557
|
-
if recipient_claim.lamports() == 0 {
|
|
558
|
-
let rent = Rent::get()?;
|
|
559
|
-
let space = 8 + RecipientClaim::LEN;
|
|
560
|
-
let lamports = rent.minimum_balance(space);
|
|
561
|
-
|
|
562
|
-
invoke_signed(
|
|
563
|
-
&system_instruction::create_account(
|
|
564
|
-
sender.key,
|
|
565
|
-
recipient_claim.key,
|
|
566
|
-
lamports,
|
|
567
|
-
space as u64,
|
|
568
|
-
program_id,
|
|
569
|
-
),
|
|
570
|
-
&[
|
|
571
|
-
sender.clone(),
|
|
572
|
-
recipient_claim.clone(),
|
|
573
|
-
system_program.clone(),
|
|
574
|
-
],
|
|
575
|
-
&[&[b"claim", to.as_ref(), &[claim_bump]]],
|
|
576
|
-
)?;
|
|
577
|
-
|
|
578
|
-
// Initialize claim account
|
|
579
|
-
let mut claim_data = recipient_claim.try_borrow_mut_data()?;
|
|
580
|
-
claim_data[0..8]
|
|
581
|
-
.copy_from_slice(&hash_discriminator("account:RecipientClaim").to_le_bytes());
|
|
582
|
-
|
|
583
|
-
let claim_state = RecipientClaim {
|
|
584
|
-
recipient: to,
|
|
585
|
-
amount: 0,
|
|
586
|
-
timestamp: 0,
|
|
587
|
-
bump: claim_bump,
|
|
588
|
-
};
|
|
589
|
-
|
|
590
|
-
claim_state.serialize(&mut &mut claim_data[8..])?;
|
|
591
|
-
drop(claim_data);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
// Transfer effective fee (may be discounted)
|
|
595
|
-
if effective_fee > 0 {
|
|
596
|
-
invoke(
|
|
597
|
-
&spl_token::instruction::transfer(
|
|
598
|
-
token_program.key,
|
|
599
|
-
sender_usdc.key,
|
|
600
|
-
mailer_usdc.key,
|
|
601
|
-
sender.key,
|
|
602
|
-
&[],
|
|
603
|
-
effective_fee,
|
|
604
|
-
)?,
|
|
605
|
-
&[
|
|
606
|
-
sender_usdc.clone(),
|
|
607
|
-
mailer_usdc.clone(),
|
|
608
|
-
sender.clone(),
|
|
609
|
-
token_program.clone(),
|
|
610
|
-
],
|
|
611
|
-
)?;
|
|
612
|
-
|
|
613
|
-
// Record revenue shares (only if fee > 0)
|
|
614
|
-
record_shares(recipient_claim, mailer_account, to, effective_fee)?;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
msg!("Priority mail sent from {} to {}: {} (revenue share enabled, resolve sender: {}, effective fee: {})", sender.key, to, subject, _resolve_sender_to_name, effective_fee);
|
|
618
|
-
} else {
|
|
619
|
-
// Standard mode: 10% fee only, no revenue sharing
|
|
620
|
-
let owner_fee = (effective_fee * 10) / 100; // 10% of effective fee
|
|
621
|
-
|
|
622
|
-
// Transfer only owner fee (10%)
|
|
623
|
-
if owner_fee > 0 {
|
|
624
|
-
invoke(
|
|
625
|
-
&spl_token::instruction::transfer(
|
|
626
|
-
token_program.key,
|
|
627
|
-
sender_usdc.key,
|
|
628
|
-
mailer_usdc.key,
|
|
629
|
-
sender.key,
|
|
630
|
-
&[],
|
|
631
|
-
owner_fee,
|
|
632
|
-
)?,
|
|
633
|
-
&[
|
|
634
|
-
sender_usdc.clone(),
|
|
635
|
-
mailer_usdc.clone(),
|
|
636
|
-
sender.clone(),
|
|
637
|
-
token_program.clone(),
|
|
638
|
-
],
|
|
639
|
-
)?;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
// Update owner claimable
|
|
643
|
-
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
644
|
-
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
645
|
-
mailer_state.owner_claimable += owner_fee;
|
|
646
|
-
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
647
|
-
|
|
648
|
-
msg!(
|
|
649
|
-
"Standard mail sent from {} to {}: {} (resolve sender: {}, effective fee: {})",
|
|
650
|
-
sender.key,
|
|
651
|
-
to,
|
|
652
|
-
subject,
|
|
653
|
-
_resolve_sender_to_name,
|
|
654
|
-
effective_fee
|
|
459
|
+
let (claim_pda, claim_bump) = Pubkey::find_program_address(
|
|
460
|
+
&[b"claim", to.as_ref()],
|
|
461
|
+
program_id
|
|
655
462
|
);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
Ok(())
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
/// Send prepared message with optional revenue sharing (references off-chain content via mailId)
|
|
662
|
-
fn process_send_prepared(
|
|
663
|
-
program_id: &Pubkey,
|
|
664
|
-
accounts: &[AccountInfo],
|
|
665
|
-
to: Pubkey,
|
|
666
|
-
mail_id: String,
|
|
667
|
-
revenue_share_to_receiver: bool,
|
|
668
|
-
_resolve_sender_to_name: bool,
|
|
669
|
-
) -> ProgramResult {
|
|
670
|
-
let account_iter = &mut accounts.iter();
|
|
671
|
-
let sender = next_account_info(account_iter)?;
|
|
672
|
-
let recipient_claim = next_account_info(account_iter)?;
|
|
673
|
-
let mailer_account = next_account_info(account_iter)?;
|
|
674
|
-
let sender_usdc = next_account_info(account_iter)?;
|
|
675
|
-
let mailer_usdc = next_account_info(account_iter)?;
|
|
676
|
-
let token_program = next_account_info(account_iter)?;
|
|
677
|
-
let system_program = next_account_info(account_iter)?;
|
|
678
|
-
|
|
679
|
-
if !sender.is_signer {
|
|
680
|
-
return Err(ProgramError::MissingRequiredSignature);
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
// Load mailer state
|
|
684
|
-
let (mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
685
|
-
let mailer_data = mailer_account.try_borrow_data()?;
|
|
686
|
-
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
687
|
-
drop(mailer_data);
|
|
688
|
-
|
|
689
|
-
assert_token_program(token_program)?;
|
|
690
|
-
assert_token_account(sender_usdc, sender.key, &mailer_state.usdc_mint)?;
|
|
691
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
692
|
-
|
|
693
|
-
// Check if contract is paused
|
|
694
|
-
if mailer_state.paused {
|
|
695
|
-
return Err(MailerError::ContractPaused.into());
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
// Calculate effective fee based on custom discount (if any)
|
|
699
|
-
let effective_fee =
|
|
700
|
-
calculate_fee_with_discount(program_id, sender.key, accounts, mailer_state.send_fee)?;
|
|
701
|
-
|
|
702
|
-
if revenue_share_to_receiver {
|
|
703
|
-
// Priority mode: full fee with revenue sharing
|
|
704
|
-
|
|
705
|
-
// Create or load recipient claim account
|
|
706
|
-
let (claim_pda, claim_bump) =
|
|
707
|
-
Pubkey::find_program_address(&[b"claim", to.as_ref()], program_id);
|
|
708
463
|
|
|
709
464
|
if recipient_claim.key != &claim_pda {
|
|
710
465
|
return Err(MailerError::InvalidPDA.into());
|
|
@@ -724,18 +479,13 @@ fn process_send_prepared(
|
|
|
724
479
|
space as u64,
|
|
725
480
|
program_id,
|
|
726
481
|
),
|
|
727
|
-
&[
|
|
728
|
-
sender.clone(),
|
|
729
|
-
recipient_claim.clone(),
|
|
730
|
-
system_program.clone(),
|
|
731
|
-
],
|
|
482
|
+
&[sender.clone(), recipient_claim.clone(), system_program.clone()],
|
|
732
483
|
&[&[b"claim", to.as_ref(), &[claim_bump]]],
|
|
733
484
|
)?;
|
|
734
485
|
|
|
735
486
|
// Initialize claim account
|
|
736
487
|
let mut claim_data = recipient_claim.try_borrow_mut_data()?;
|
|
737
|
-
claim_data[0..8]
|
|
738
|
-
.copy_from_slice(&hash_discriminator("account:RecipientClaim").to_le_bytes());
|
|
488
|
+
claim_data[0..8].copy_from_slice(&hash_discriminator("account:RecipientClaim").to_le_bytes());
|
|
739
489
|
|
|
740
490
|
let claim_state = RecipientClaim {
|
|
741
491
|
recipient: to,
|
|
@@ -771,7 +521,7 @@ fn process_send_prepared(
|
|
|
771
521
|
record_shares(recipient_claim, mailer_account, to, effective_fee)?;
|
|
772
522
|
}
|
|
773
523
|
|
|
774
|
-
msg!("Priority
|
|
524
|
+
msg!("Priority mail sent from {} to {}: {} (revenue share enabled, resolve sender: {}, effective fee: {})", sender.key, to, subject, _resolve_sender_to_name, effective_fee);
|
|
775
525
|
} else {
|
|
776
526
|
// Standard mode: 10% fee only, no revenue sharing
|
|
777
527
|
let owner_fee = (effective_fee * 10) / 100; // 10% of effective fee
|
|
@@ -802,14 +552,7 @@ fn process_send_prepared(
|
|
|
802
552
|
mailer_state.owner_claimable += owner_fee;
|
|
803
553
|
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
804
554
|
|
|
805
|
-
msg!(
|
|
806
|
-
"Standard prepared mail sent from {} to {} (mailId: {}, resolve sender: {}, effective fee: {})",
|
|
807
|
-
sender.key,
|
|
808
|
-
to,
|
|
809
|
-
mail_id,
|
|
810
|
-
_resolve_sender_to_name,
|
|
811
|
-
effective_fee
|
|
812
|
-
);
|
|
555
|
+
msg!("Standard mail sent from {} to {}: {} (resolve sender: {}, effective fee: {})", sender.key, to, subject, _resolve_sender_to_name, effective_fee);
|
|
813
556
|
}
|
|
814
557
|
|
|
815
558
|
Ok(())
|
|
@@ -835,23 +578,17 @@ fn process_send_to_email(
|
|
|
835
578
|
}
|
|
836
579
|
|
|
837
580
|
// Load mailer state
|
|
838
|
-
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
839
581
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
840
582
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
841
583
|
drop(mailer_data);
|
|
842
584
|
|
|
843
|
-
assert_token_program(token_program)?;
|
|
844
|
-
assert_token_account(sender_usdc, sender.key, &mailer_state.usdc_mint)?;
|
|
845
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
846
|
-
|
|
847
585
|
// Check if contract is paused
|
|
848
586
|
if mailer_state.paused {
|
|
849
587
|
return Err(MailerError::ContractPaused.into());
|
|
850
588
|
}
|
|
851
589
|
|
|
852
590
|
// Calculate effective fee based on custom discount (if any)
|
|
853
|
-
let effective_fee =
|
|
854
|
-
calculate_fee_with_discount(_program_id, sender.key, accounts, mailer_state.send_fee)?;
|
|
591
|
+
let effective_fee = calculate_fee_with_discount(_program_id, sender.key, accounts, mailer_state.send_fee)?;
|
|
855
592
|
|
|
856
593
|
// Calculate 10% owner fee (no revenue share since no wallet address)
|
|
857
594
|
let owner_fee = (effective_fee * 10) / 100;
|
|
@@ -884,13 +621,7 @@ fn process_send_to_email(
|
|
|
884
621
|
mailer_state.owner_claimable += owner_fee;
|
|
885
622
|
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
886
623
|
|
|
887
|
-
msg!(
|
|
888
|
-
"Mail sent from {} to email {}: {} (effective fee: {})",
|
|
889
|
-
sender.key,
|
|
890
|
-
to_email,
|
|
891
|
-
subject,
|
|
892
|
-
effective_fee
|
|
893
|
-
);
|
|
624
|
+
msg!("Mail sent from {} to email {}: {} (effective fee: {})", sender.key, to_email, subject, effective_fee);
|
|
894
625
|
|
|
895
626
|
Ok(())
|
|
896
627
|
}
|
|
@@ -909,225 +640,56 @@ fn process_send_prepared_to_email(
|
|
|
909
640
|
let mailer_usdc = next_account_info(account_iter)?;
|
|
910
641
|
let token_program = next_account_info(account_iter)?;
|
|
911
642
|
|
|
912
|
-
if !sender.is_signer {
|
|
913
|
-
return Err(ProgramError::MissingRequiredSignature);
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
// Load mailer state
|
|
917
|
-
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
918
|
-
let mailer_data = mailer_account.try_borrow_data()?;
|
|
919
|
-
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
920
|
-
drop(mailer_data);
|
|
921
|
-
|
|
922
|
-
assert_token_program(token_program)?;
|
|
923
|
-
assert_token_account(sender_usdc, sender.key, &mailer_state.usdc_mint)?;
|
|
924
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
925
|
-
|
|
926
|
-
// Check if contract is paused
|
|
927
|
-
if mailer_state.paused {
|
|
928
|
-
return Err(MailerError::ContractPaused.into());
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
// Calculate effective fee based on custom discount (if any)
|
|
932
|
-
let effective_fee =
|
|
933
|
-
calculate_fee_with_discount(_program_id, sender.key, accounts, mailer_state.send_fee)?;
|
|
934
|
-
|
|
935
|
-
// Calculate 10% owner fee (no revenue share since no wallet address)
|
|
936
|
-
let owner_fee = (effective_fee * 10) / 100;
|
|
937
|
-
|
|
938
|
-
// Transfer fee from sender to mailer
|
|
939
|
-
if owner_fee > 0 {
|
|
940
|
-
let transfer_ix = spl_token::instruction::transfer(
|
|
941
|
-
token_program.key,
|
|
942
|
-
sender_usdc.key,
|
|
943
|
-
mailer_usdc.key,
|
|
944
|
-
sender.key,
|
|
945
|
-
&[],
|
|
946
|
-
owner_fee,
|
|
947
|
-
)?;
|
|
948
|
-
|
|
949
|
-
invoke(
|
|
950
|
-
&transfer_ix,
|
|
951
|
-
&[
|
|
952
|
-
sender_usdc.clone(),
|
|
953
|
-
mailer_usdc.clone(),
|
|
954
|
-
sender.clone(),
|
|
955
|
-
token_program.clone(),
|
|
956
|
-
],
|
|
957
|
-
)?;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
// Update owner claimable
|
|
961
|
-
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
962
|
-
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
963
|
-
mailer_state.owner_claimable += owner_fee;
|
|
964
|
-
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
965
|
-
|
|
966
|
-
msg!(
|
|
967
|
-
"Prepared mail sent from {} to email {} (mailId: {}, effective fee: {})",
|
|
968
|
-
sender.key,
|
|
969
|
-
to_email,
|
|
970
|
-
mail_id,
|
|
971
|
-
effective_fee
|
|
972
|
-
);
|
|
973
|
-
|
|
974
|
-
Ok(())
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
/// Send message through webhook (references webhook by webhookId)
|
|
978
|
-
fn process_send_through_webhook(
|
|
979
|
-
program_id: &Pubkey,
|
|
980
|
-
accounts: &[AccountInfo],
|
|
981
|
-
to: Pubkey,
|
|
982
|
-
webhook_id: String,
|
|
983
|
-
revenue_share_to_receiver: bool,
|
|
984
|
-
_resolve_sender_to_name: bool,
|
|
985
|
-
) -> ProgramResult {
|
|
986
|
-
let account_iter = &mut accounts.iter();
|
|
987
|
-
let sender = next_account_info(account_iter)?;
|
|
988
|
-
let recipient_claim = next_account_info(account_iter)?;
|
|
989
|
-
let mailer_account = next_account_info(account_iter)?;
|
|
990
|
-
let sender_usdc = next_account_info(account_iter)?;
|
|
991
|
-
let mailer_usdc = next_account_info(account_iter)?;
|
|
992
|
-
let token_program = next_account_info(account_iter)?;
|
|
993
|
-
let system_program = next_account_info(account_iter)?;
|
|
994
|
-
|
|
995
|
-
if !sender.is_signer {
|
|
996
|
-
return Err(ProgramError::MissingRequiredSignature);
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
// Load mailer state
|
|
1000
|
-
let (mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
1001
|
-
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1002
|
-
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
1003
|
-
drop(mailer_data);
|
|
1004
|
-
|
|
1005
|
-
assert_token_program(token_program)?;
|
|
1006
|
-
assert_token_account(sender_usdc, sender.key, &mailer_state.usdc_mint)?;
|
|
1007
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
1008
|
-
|
|
1009
|
-
// Check if contract is paused
|
|
1010
|
-
if mailer_state.paused {
|
|
1011
|
-
return Err(MailerError::ContractPaused.into());
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
// Calculate effective fee based on custom discount (if any)
|
|
1015
|
-
let effective_fee =
|
|
1016
|
-
calculate_fee_with_discount(program_id, sender.key, accounts, mailer_state.send_fee)?;
|
|
1017
|
-
|
|
1018
|
-
if revenue_share_to_receiver {
|
|
1019
|
-
// Priority mode: full fee with revenue sharing
|
|
1020
|
-
|
|
1021
|
-
// Create or load recipient claim account
|
|
1022
|
-
let (claim_pda, claim_bump) =
|
|
1023
|
-
Pubkey::find_program_address(&[b"claim", to.as_ref()], program_id);
|
|
1024
|
-
|
|
1025
|
-
if recipient_claim.key != &claim_pda {
|
|
1026
|
-
return Err(MailerError::InvalidPDA.into());
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
// Create claim account if needed
|
|
1030
|
-
if recipient_claim.lamports() == 0 {
|
|
1031
|
-
let rent = Rent::get()?;
|
|
1032
|
-
let space = 8 + RecipientClaim::LEN;
|
|
1033
|
-
let lamports = rent.minimum_balance(space);
|
|
1034
|
-
|
|
1035
|
-
invoke_signed(
|
|
1036
|
-
&system_instruction::create_account(
|
|
1037
|
-
sender.key,
|
|
1038
|
-
recipient_claim.key,
|
|
1039
|
-
lamports,
|
|
1040
|
-
space as u64,
|
|
1041
|
-
program_id,
|
|
1042
|
-
),
|
|
1043
|
-
&[
|
|
1044
|
-
sender.clone(),
|
|
1045
|
-
recipient_claim.clone(),
|
|
1046
|
-
system_program.clone(),
|
|
1047
|
-
],
|
|
1048
|
-
&[&[b"claim", to.as_ref(), &[claim_bump]]],
|
|
1049
|
-
)?;
|
|
1050
|
-
|
|
1051
|
-
// Initialize claim account
|
|
1052
|
-
let mut claim_data = recipient_claim.try_borrow_mut_data()?;
|
|
1053
|
-
claim_data[0..8]
|
|
1054
|
-
.copy_from_slice(&hash_discriminator("account:RecipientClaim").to_le_bytes());
|
|
1055
|
-
|
|
1056
|
-
let claim_state = RecipientClaim {
|
|
1057
|
-
recipient: to,
|
|
1058
|
-
amount: 0,
|
|
1059
|
-
timestamp: 0,
|
|
1060
|
-
bump: claim_bump,
|
|
1061
|
-
};
|
|
1062
|
-
|
|
1063
|
-
claim_state.serialize(&mut &mut claim_data[8..])?;
|
|
1064
|
-
drop(claim_data);
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
// Transfer effective fee (may be discounted)
|
|
1068
|
-
if effective_fee > 0 {
|
|
1069
|
-
invoke(
|
|
1070
|
-
&spl_token::instruction::transfer(
|
|
1071
|
-
token_program.key,
|
|
1072
|
-
sender_usdc.key,
|
|
1073
|
-
mailer_usdc.key,
|
|
1074
|
-
sender.key,
|
|
1075
|
-
&[],
|
|
1076
|
-
effective_fee,
|
|
1077
|
-
)?,
|
|
1078
|
-
&[
|
|
1079
|
-
sender_usdc.clone(),
|
|
1080
|
-
mailer_usdc.clone(),
|
|
1081
|
-
sender.clone(),
|
|
1082
|
-
token_program.clone(),
|
|
1083
|
-
],
|
|
1084
|
-
)?;
|
|
643
|
+
if !sender.is_signer {
|
|
644
|
+
return Err(ProgramError::MissingRequiredSignature);
|
|
645
|
+
}
|
|
1085
646
|
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
647
|
+
// Load mailer state
|
|
648
|
+
let mailer_data = mailer_account.try_borrow_data()?;
|
|
649
|
+
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
650
|
+
drop(mailer_data);
|
|
1089
651
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
652
|
+
// Check if contract is paused
|
|
653
|
+
if mailer_state.paused {
|
|
654
|
+
return Err(MailerError::ContractPaused.into());
|
|
655
|
+
}
|
|
1094
656
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
invoke(
|
|
1098
|
-
&spl_token::instruction::transfer(
|
|
1099
|
-
token_program.key,
|
|
1100
|
-
sender_usdc.key,
|
|
1101
|
-
mailer_usdc.key,
|
|
1102
|
-
sender.key,
|
|
1103
|
-
&[],
|
|
1104
|
-
owner_fee,
|
|
1105
|
-
)?,
|
|
1106
|
-
&[
|
|
1107
|
-
sender_usdc.clone(),
|
|
1108
|
-
mailer_usdc.clone(),
|
|
1109
|
-
sender.clone(),
|
|
1110
|
-
token_program.clone(),
|
|
1111
|
-
],
|
|
1112
|
-
)?;
|
|
1113
|
-
}
|
|
657
|
+
// Calculate effective fee based on custom discount (if any)
|
|
658
|
+
let effective_fee = calculate_fee_with_discount(_program_id, sender.key, accounts, mailer_state.send_fee)?;
|
|
1114
659
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
1118
|
-
mailer_state.owner_claimable += owner_fee;
|
|
1119
|
-
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
660
|
+
// Calculate 10% owner fee (no revenue share since no wallet address)
|
|
661
|
+
let owner_fee = (effective_fee * 10) / 100;
|
|
1120
662
|
|
|
1121
|
-
|
|
1122
|
-
|
|
663
|
+
// Transfer fee from sender to mailer
|
|
664
|
+
if owner_fee > 0 {
|
|
665
|
+
let transfer_ix = spl_token::instruction::transfer(
|
|
666
|
+
token_program.key,
|
|
667
|
+
sender_usdc.key,
|
|
668
|
+
mailer_usdc.key,
|
|
1123
669
|
sender.key,
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
670
|
+
&[],
|
|
671
|
+
owner_fee,
|
|
672
|
+
)?;
|
|
673
|
+
|
|
674
|
+
invoke(
|
|
675
|
+
&transfer_ix,
|
|
676
|
+
&[
|
|
677
|
+
sender_usdc.clone(),
|
|
678
|
+
mailer_usdc.clone(),
|
|
679
|
+
sender.clone(),
|
|
680
|
+
token_program.clone(),
|
|
681
|
+
],
|
|
682
|
+
)?;
|
|
1129
683
|
}
|
|
1130
684
|
|
|
685
|
+
// Update owner claimable
|
|
686
|
+
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
687
|
+
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
688
|
+
mailer_state.owner_claimable += owner_fee;
|
|
689
|
+
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
690
|
+
|
|
691
|
+
msg!("Prepared mail sent from {} to email {} (mailId: {}, effective fee: {})", sender.key, to_email, mail_id, effective_fee);
|
|
692
|
+
|
|
1131
693
|
Ok(())
|
|
1132
694
|
}
|
|
1133
695
|
|
|
@@ -1145,13 +707,6 @@ fn process_claim_recipient_share(_program_id: &Pubkey, accounts: &[AccountInfo])
|
|
|
1145
707
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1146
708
|
}
|
|
1147
709
|
|
|
1148
|
-
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
1149
|
-
let (claim_pda, _) =
|
|
1150
|
-
Pubkey::find_program_address(&[b"claim", recipient.key.as_ref()], _program_id);
|
|
1151
|
-
if recipient_claim.key != &claim_pda {
|
|
1152
|
-
return Err(MailerError::InvalidPDA.into());
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
710
|
// Load claim state
|
|
1156
711
|
let mut claim_data = recipient_claim.try_borrow_mut_data()?;
|
|
1157
712
|
let mut claim_state: RecipientClaim = BorshDeserialize::deserialize(&mut &claim_data[8..])?;
|
|
@@ -1178,11 +733,6 @@ fn process_claim_recipient_share(_program_id: &Pubkey, accounts: &[AccountInfo])
|
|
|
1178
733
|
// Load mailer state for PDA signing
|
|
1179
734
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1180
735
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
1181
|
-
drop(mailer_data);
|
|
1182
|
-
|
|
1183
|
-
assert_token_program(token_program)?;
|
|
1184
|
-
assert_token_account(recipient_usdc, recipient.key, &mailer_state.usdc_mint)?;
|
|
1185
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
1186
736
|
|
|
1187
737
|
// Transfer USDC from mailer to recipient
|
|
1188
738
|
invoke_signed(
|
|
@@ -1220,8 +770,6 @@ fn process_claim_owner_share(_program_id: &Pubkey, accounts: &[AccountInfo]) ->
|
|
|
1220
770
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1221
771
|
}
|
|
1222
772
|
|
|
1223
|
-
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
1224
|
-
|
|
1225
773
|
// Load and update mailer state
|
|
1226
774
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1227
775
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1239,10 +787,6 @@ fn process_claim_owner_share(_program_id: &Pubkey, accounts: &[AccountInfo]) ->
|
|
|
1239
787
|
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
1240
788
|
drop(mailer_data);
|
|
1241
789
|
|
|
1242
|
-
assert_token_program(token_program)?;
|
|
1243
|
-
assert_token_account(owner_usdc, owner.key, &mailer_state.usdc_mint)?;
|
|
1244
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
1245
|
-
|
|
1246
790
|
// Transfer USDC from mailer to owner
|
|
1247
791
|
invoke_signed(
|
|
1248
792
|
&spl_token::instruction::transfer(
|
|
@@ -1276,8 +820,6 @@ fn process_set_fee(_program_id: &Pubkey, accounts: &[AccountInfo], new_fee: u64)
|
|
|
1276
820
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1277
821
|
}
|
|
1278
822
|
|
|
1279
|
-
assert_mailer_account(_program_id, mailer_account)?;
|
|
1280
|
-
|
|
1281
823
|
// Load and update mailer state
|
|
1282
824
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1283
825
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1318,25 +860,21 @@ fn process_delegate_to(
|
|
|
1318
860
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1319
861
|
}
|
|
1320
862
|
|
|
1321
|
-
let (mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
1322
|
-
|
|
1323
863
|
// Load mailer state
|
|
1324
864
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1325
865
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
1326
866
|
drop(mailer_data);
|
|
1327
867
|
|
|
1328
|
-
assert_token_program(token_program)?;
|
|
1329
|
-
assert_token_account(delegator_usdc, delegator.key, &mailer_state.usdc_mint)?;
|
|
1330
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
1331
|
-
|
|
1332
868
|
// Check if contract is paused
|
|
1333
869
|
if mailer_state.paused {
|
|
1334
870
|
return Err(MailerError::ContractPaused.into());
|
|
1335
871
|
}
|
|
1336
872
|
|
|
1337
873
|
// Verify delegation account PDA
|
|
1338
|
-
let (delegation_pda, delegation_bump) =
|
|
1339
|
-
|
|
874
|
+
let (delegation_pda, delegation_bump) = Pubkey::find_program_address(
|
|
875
|
+
&[b"delegation", delegator.key.as_ref()],
|
|
876
|
+
program_id
|
|
877
|
+
);
|
|
1340
878
|
|
|
1341
879
|
if delegation_account.key != &delegation_pda {
|
|
1342
880
|
return Err(MailerError::InvalidPDA.into());
|
|
@@ -1366,8 +904,7 @@ fn process_delegate_to(
|
|
|
1366
904
|
|
|
1367
905
|
// Initialize delegation account
|
|
1368
906
|
let mut delegation_data = delegation_account.try_borrow_mut_data()?;
|
|
1369
|
-
delegation_data[0..8]
|
|
1370
|
-
.copy_from_slice(&hash_discriminator("account:Delegation").to_le_bytes());
|
|
907
|
+
delegation_data[0..8].copy_from_slice(&hash_discriminator("account:Delegation").to_le_bytes());
|
|
1371
908
|
|
|
1372
909
|
let delegation_state = Delegation {
|
|
1373
910
|
delegator: *delegator.key,
|
|
@@ -1403,8 +940,7 @@ fn process_delegate_to(
|
|
|
1403
940
|
|
|
1404
941
|
// Update delegation
|
|
1405
942
|
let mut delegation_data = delegation_account.try_borrow_mut_data()?;
|
|
1406
|
-
let mut delegation_state: Delegation =
|
|
1407
|
-
BorshDeserialize::deserialize(&mut &delegation_data[8..])?;
|
|
943
|
+
let mut delegation_state: Delegation = BorshDeserialize::deserialize(&mut &delegation_data[8..])?;
|
|
1408
944
|
delegation_state.delegate = delegate;
|
|
1409
945
|
delegation_state.serialize(&mut &mut delegation_data[8..])?;
|
|
1410
946
|
|
|
@@ -1413,31 +949,18 @@ fn process_delegate_to(
|
|
|
1413
949
|
}
|
|
1414
950
|
|
|
1415
951
|
/// Reject delegation
|
|
1416
|
-
fn process_reject_delegation(
|
|
952
|
+
fn process_reject_delegation(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
|
|
1417
953
|
let account_iter = &mut accounts.iter();
|
|
1418
954
|
let rejector = next_account_info(account_iter)?;
|
|
1419
955
|
let delegation_account = next_account_info(account_iter)?;
|
|
1420
|
-
let mailer_account = next_account_info(account_iter)?;
|
|
1421
956
|
|
|
1422
957
|
if !rejector.is_signer {
|
|
1423
958
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1424
959
|
}
|
|
1425
960
|
|
|
1426
|
-
// Verify mailer state PDA and ensure contract is not paused
|
|
1427
|
-
let (_mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
1428
|
-
|
|
1429
|
-
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1430
|
-
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
1431
|
-
drop(mailer_data);
|
|
1432
|
-
|
|
1433
|
-
if mailer_state.paused {
|
|
1434
|
-
return Err(MailerError::ContractPaused.into());
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
961
|
// Load and update delegation state
|
|
1438
962
|
let mut delegation_data = delegation_account.try_borrow_mut_data()?;
|
|
1439
|
-
let mut delegation_state: Delegation =
|
|
1440
|
-
BorshDeserialize::deserialize(&mut &delegation_data[8..])?;
|
|
963
|
+
let mut delegation_state: Delegation = BorshDeserialize::deserialize(&mut &delegation_data[8..])?;
|
|
1441
964
|
|
|
1442
965
|
// Verify the rejector is the current delegate
|
|
1443
966
|
if delegation_state.delegate != Some(*rejector.key) {
|
|
@@ -1465,8 +988,6 @@ fn process_set_delegation_fee(
|
|
|
1465
988
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1466
989
|
}
|
|
1467
990
|
|
|
1468
|
-
assert_mailer_account(_program_id, mailer_account)?;
|
|
1469
|
-
|
|
1470
991
|
// Load and update mailer state
|
|
1471
992
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1472
993
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1507,8 +1028,6 @@ fn process_set_custom_fee_percentage(
|
|
|
1507
1028
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1508
1029
|
}
|
|
1509
1030
|
|
|
1510
|
-
assert_mailer_account(program_id, mailer_account)?;
|
|
1511
|
-
|
|
1512
1031
|
// Load mailer state and verify owner
|
|
1513
1032
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1514
1033
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1529,8 +1048,10 @@ fn process_set_custom_fee_percentage(
|
|
|
1529
1048
|
}
|
|
1530
1049
|
|
|
1531
1050
|
// Verify fee discount account PDA
|
|
1532
|
-
let (discount_pda, bump) =
|
|
1533
|
-
|
|
1051
|
+
let (discount_pda, bump) = Pubkey::find_program_address(
|
|
1052
|
+
&[b"discount", account.as_ref()],
|
|
1053
|
+
program_id
|
|
1054
|
+
);
|
|
1534
1055
|
|
|
1535
1056
|
if fee_discount_account.key != &discount_pda {
|
|
1536
1057
|
return Err(MailerError::InvalidPDA.into());
|
|
@@ -1550,18 +1071,13 @@ fn process_set_custom_fee_percentage(
|
|
|
1550
1071
|
space as u64,
|
|
1551
1072
|
program_id,
|
|
1552
1073
|
),
|
|
1553
|
-
&[
|
|
1554
|
-
payer.clone(),
|
|
1555
|
-
fee_discount_account.clone(),
|
|
1556
|
-
system_program.clone(),
|
|
1557
|
-
],
|
|
1074
|
+
&[payer.clone(), fee_discount_account.clone(), system_program.clone()],
|
|
1558
1075
|
&[&[b"discount", account.as_ref(), &[bump]]],
|
|
1559
1076
|
)?;
|
|
1560
1077
|
|
|
1561
1078
|
// Initialize discount account
|
|
1562
1079
|
let mut discount_data = fee_discount_account.try_borrow_mut_data()?;
|
|
1563
|
-
discount_data[0..8]
|
|
1564
|
-
.copy_from_slice(&hash_discriminator("account:FeeDiscount").to_le_bytes());
|
|
1080
|
+
discount_data[0..8].copy_from_slice(&hash_discriminator("account:FeeDiscount").to_le_bytes());
|
|
1565
1081
|
|
|
1566
1082
|
let fee_discount = FeeDiscount {
|
|
1567
1083
|
account,
|
|
@@ -1573,8 +1089,7 @@ fn process_set_custom_fee_percentage(
|
|
|
1573
1089
|
} else {
|
|
1574
1090
|
// Update existing discount account
|
|
1575
1091
|
let mut discount_data = fee_discount_account.try_borrow_mut_data()?;
|
|
1576
|
-
let mut fee_discount: FeeDiscount =
|
|
1577
|
-
BorshDeserialize::deserialize(&mut &discount_data[8..])?;
|
|
1092
|
+
let mut fee_discount: FeeDiscount = BorshDeserialize::deserialize(&mut &discount_data[8..])?;
|
|
1578
1093
|
fee_discount.discount = 100 - percentage; // Store as discount
|
|
1579
1094
|
fee_discount.serialize(&mut &mut discount_data[8..])?;
|
|
1580
1095
|
}
|
|
@@ -1598,8 +1113,6 @@ fn process_clear_custom_fee_percentage(
|
|
|
1598
1113
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1599
1114
|
}
|
|
1600
1115
|
|
|
1601
|
-
assert_mailer_account(program_id, mailer_account)?;
|
|
1602
|
-
|
|
1603
1116
|
// Load mailer state and verify owner
|
|
1604
1117
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1605
1118
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1615,8 +1128,10 @@ fn process_clear_custom_fee_percentage(
|
|
|
1615
1128
|
}
|
|
1616
1129
|
|
|
1617
1130
|
// Verify fee discount account PDA
|
|
1618
|
-
let (discount_pda, _) =
|
|
1619
|
-
|
|
1131
|
+
let (discount_pda, _) = Pubkey::find_program_address(
|
|
1132
|
+
&[b"discount", account.as_ref()],
|
|
1133
|
+
program_id
|
|
1134
|
+
);
|
|
1620
1135
|
|
|
1621
1136
|
if fee_discount_account.key != &discount_pda {
|
|
1622
1137
|
return Err(MailerError::InvalidPDA.into());
|
|
@@ -1625,57 +1140,15 @@ fn process_clear_custom_fee_percentage(
|
|
|
1625
1140
|
// Clear by setting discount to 0 (no discount = 100% fee = default behavior)
|
|
1626
1141
|
if fee_discount_account.lamports() > 0 {
|
|
1627
1142
|
let mut discount_data = fee_discount_account.try_borrow_mut_data()?;
|
|
1628
|
-
let mut fee_discount: FeeDiscount =
|
|
1629
|
-
BorshDeserialize::deserialize(&mut &discount_data[8..])?;
|
|
1143
|
+
let mut fee_discount: FeeDiscount = BorshDeserialize::deserialize(&mut &discount_data[8..])?;
|
|
1630
1144
|
fee_discount.discount = 0; // 0 discount = 100% fee = default
|
|
1631
1145
|
fee_discount.serialize(&mut &mut discount_data[8..])?;
|
|
1632
1146
|
}
|
|
1633
1147
|
|
|
1634
|
-
msg!(
|
|
1635
|
-
"Custom fee percentage cleared for {} (reset to 100%)",
|
|
1636
|
-
account
|
|
1637
|
-
);
|
|
1638
|
-
Ok(())
|
|
1639
|
-
}
|
|
1640
|
-
|
|
1641
|
-
fn assert_token_program(token_program: &AccountInfo) -> Result<(), ProgramError> {
|
|
1642
|
-
if token_program.key != &spl_token::id() {
|
|
1643
|
-
return Err(MailerError::InvalidTokenProgram.into());
|
|
1644
|
-
}
|
|
1645
|
-
Ok(())
|
|
1646
|
-
}
|
|
1647
|
-
|
|
1648
|
-
fn assert_token_account(
|
|
1649
|
-
token_account_info: &AccountInfo,
|
|
1650
|
-
expected_owner: &Pubkey,
|
|
1651
|
-
expected_mint: &Pubkey,
|
|
1652
|
-
) -> Result<(), ProgramError> {
|
|
1653
|
-
let data = token_account_info.try_borrow_data()?;
|
|
1654
|
-
let token_account = TokenAccount::unpack(&data)?;
|
|
1655
|
-
drop(data);
|
|
1656
|
-
|
|
1657
|
-
if token_account.owner != *expected_owner {
|
|
1658
|
-
return Err(MailerError::InvalidAccountOwner.into());
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
if token_account.mint != *expected_mint {
|
|
1662
|
-
return Err(MailerError::InvalidMint.into());
|
|
1663
|
-
}
|
|
1664
|
-
|
|
1148
|
+
msg!("Custom fee percentage cleared for {} (reset to 100%)", account);
|
|
1665
1149
|
Ok(())
|
|
1666
1150
|
}
|
|
1667
1151
|
|
|
1668
|
-
fn assert_mailer_account(
|
|
1669
|
-
program_id: &Pubkey,
|
|
1670
|
-
mailer_account: &AccountInfo,
|
|
1671
|
-
) -> Result<(Pubkey, u8), ProgramError> {
|
|
1672
|
-
let (mailer_pda, bump) = Pubkey::find_program_address(&[b"mailer"], program_id);
|
|
1673
|
-
if mailer_account.key != &mailer_pda {
|
|
1674
|
-
return Err(MailerError::InvalidPDA.into());
|
|
1675
|
-
}
|
|
1676
|
-
Ok((mailer_pda, bump))
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
1152
|
/// Record revenue shares for priority messages
|
|
1680
1153
|
fn record_shares(
|
|
1681
1154
|
recipient_claim: &AccountInfo,
|
|
@@ -1702,11 +1175,7 @@ fn record_shares(
|
|
|
1702
1175
|
mailer_state.owner_claimable += owner_amount;
|
|
1703
1176
|
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
1704
1177
|
|
|
1705
|
-
msg!(
|
|
1706
|
-
"Shares recorded: recipient {}, owner {}",
|
|
1707
|
-
recipient_amount,
|
|
1708
|
-
owner_amount
|
|
1709
|
-
);
|
|
1178
|
+
msg!("Shares recorded: recipient {}, owner {}", recipient_amount, owner_amount);
|
|
1710
1179
|
Ok(())
|
|
1711
1180
|
}
|
|
1712
1181
|
|
|
@@ -1720,8 +1189,10 @@ fn calculate_fee_with_discount(
|
|
|
1720
1189
|
base_fee: u64,
|
|
1721
1190
|
) -> Result<u64, ProgramError> {
|
|
1722
1191
|
// Try to find fee discount account
|
|
1723
|
-
let (discount_pda, _) =
|
|
1724
|
-
|
|
1192
|
+
let (discount_pda, _) = Pubkey::find_program_address(
|
|
1193
|
+
&[b"discount", account.as_ref()],
|
|
1194
|
+
program_id
|
|
1195
|
+
);
|
|
1725
1196
|
|
|
1726
1197
|
// Check if any account in the accounts slice matches the discount PDA
|
|
1727
1198
|
let discount_account = accounts.iter().find(|acc| acc.key == &discount_pda);
|
|
@@ -1731,8 +1202,7 @@ fn calculate_fee_with_discount(
|
|
|
1731
1202
|
if discount_acc.lamports() > 0 {
|
|
1732
1203
|
let discount_data = discount_acc.try_borrow_data()?;
|
|
1733
1204
|
if discount_data.len() >= 8 + FeeDiscount::LEN {
|
|
1734
|
-
let fee_discount: FeeDiscount =
|
|
1735
|
-
BorshDeserialize::deserialize(&mut &discount_data[8..])?;
|
|
1205
|
+
let fee_discount: FeeDiscount = BorshDeserialize::deserialize(&mut &discount_data[8..])?;
|
|
1736
1206
|
let discount = fee_discount.discount as u64;
|
|
1737
1207
|
|
|
1738
1208
|
// Apply discount: fee = base_fee * (100 - discount) / 100
|
|
@@ -1760,8 +1230,6 @@ fn process_pause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResul
|
|
|
1760
1230
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1761
1231
|
}
|
|
1762
1232
|
|
|
1763
|
-
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
1764
|
-
|
|
1765
1233
|
// Load and update mailer state
|
|
1766
1234
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1767
1235
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1779,17 +1247,13 @@ fn process_pause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResul
|
|
|
1779
1247
|
// Set paused state
|
|
1780
1248
|
mailer_state.paused = true;
|
|
1781
1249
|
|
|
1782
|
-
assert_token_program(token_program)?;
|
|
1783
|
-
|
|
1784
1250
|
// Distribute owner claimable funds if any
|
|
1785
1251
|
if mailer_state.owner_claimable > 0 {
|
|
1786
1252
|
let amount = mailer_state.owner_claimable;
|
|
1787
1253
|
mailer_state.owner_claimable = 0;
|
|
1788
1254
|
|
|
1789
|
-
assert_token_account(owner_usdc, owner.key, &mailer_state.usdc_mint)?;
|
|
1790
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
1791
|
-
|
|
1792
1255
|
// Transfer USDC from mailer to owner
|
|
1256
|
+
let (mailer_pda, bump) = Pubkey::find_program_address(&[b"mailer"], _program_id);
|
|
1793
1257
|
invoke_signed(
|
|
1794
1258
|
&spl_token::instruction::transfer(
|
|
1795
1259
|
token_program.key,
|
|
@@ -1799,13 +1263,8 @@ fn process_pause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResul
|
|
|
1799
1263
|
&[],
|
|
1800
1264
|
amount,
|
|
1801
1265
|
)?,
|
|
1802
|
-
&[
|
|
1803
|
-
|
|
1804
|
-
owner_usdc.clone(),
|
|
1805
|
-
mailer_account.clone(),
|
|
1806
|
-
token_program.clone(),
|
|
1807
|
-
],
|
|
1808
|
-
&[&[b"mailer", &[mailer_state.bump]]],
|
|
1266
|
+
&[mailer_usdc.clone(), owner_usdc.clone(), token_program.clone()],
|
|
1267
|
+
&[&[b"mailer", &[bump]]],
|
|
1809
1268
|
)?;
|
|
1810
1269
|
|
|
1811
1270
|
msg!("Distributed owner funds during pause: {}", amount);
|
|
@@ -1813,7 +1272,7 @@ fn process_pause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResul
|
|
|
1813
1272
|
|
|
1814
1273
|
// Save updated state
|
|
1815
1274
|
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
1816
|
-
|
|
1275
|
+
|
|
1817
1276
|
msg!("Contract paused by owner: {}", owner.key);
|
|
1818
1277
|
Ok(())
|
|
1819
1278
|
}
|
|
@@ -1828,8 +1287,6 @@ fn process_unpause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramRes
|
|
|
1828
1287
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1829
1288
|
}
|
|
1830
1289
|
|
|
1831
|
-
assert_mailer_account(_program_id, mailer_account)?;
|
|
1832
|
-
|
|
1833
1290
|
// Load and update mailer state
|
|
1834
1291
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1835
1292
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1847,11 +1304,43 @@ fn process_unpause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramRes
|
|
|
1847
1304
|
// Set unpaused state
|
|
1848
1305
|
mailer_state.paused = false;
|
|
1849
1306
|
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
1850
|
-
|
|
1307
|
+
|
|
1851
1308
|
msg!("Contract unpaused by owner: {}", owner.key);
|
|
1852
1309
|
Ok(())
|
|
1853
1310
|
}
|
|
1854
1311
|
|
|
1312
|
+
/// Emergency unpause without fund distribution (owner only)
|
|
1313
|
+
fn process_emergency_unpause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
|
|
1314
|
+
let account_iter = &mut accounts.iter();
|
|
1315
|
+
let owner = next_account_info(account_iter)?;
|
|
1316
|
+
let mailer_account = next_account_info(account_iter)?;
|
|
1317
|
+
|
|
1318
|
+
if !owner.is_signer {
|
|
1319
|
+
return Err(ProgramError::MissingRequiredSignature);
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
// Load and update mailer state
|
|
1323
|
+
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1324
|
+
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
1325
|
+
|
|
1326
|
+
// Verify owner
|
|
1327
|
+
if mailer_state.owner != *owner.key {
|
|
1328
|
+
return Err(MailerError::OnlyOwner.into());
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// Check if not paused
|
|
1332
|
+
if !mailer_state.paused {
|
|
1333
|
+
return Err(MailerError::ContractNotPaused.into());
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
// Set unpaused state without fund distribution
|
|
1337
|
+
mailer_state.paused = false;
|
|
1338
|
+
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
1339
|
+
|
|
1340
|
+
msg!("Contract emergency unpaused by owner: {} - funds can be claimed manually", owner.key);
|
|
1341
|
+
Ok(())
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1855
1344
|
/// Distribute claimable funds when contract is paused
|
|
1856
1345
|
fn process_distribute_claimable_funds(
|
|
1857
1346
|
_program_id: &Pubkey,
|
|
@@ -1866,8 +1355,6 @@ fn process_distribute_claimable_funds(
|
|
|
1866
1355
|
let mailer_usdc = next_account_info(account_iter)?;
|
|
1867
1356
|
let token_program = next_account_info(account_iter)?;
|
|
1868
1357
|
|
|
1869
|
-
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
1870
|
-
|
|
1871
1358
|
// Load mailer state to check if paused
|
|
1872
1359
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1873
1360
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1884,8 +1371,6 @@ fn process_distribute_claimable_funds(
|
|
|
1884
1371
|
return Err(MailerError::InvalidPDA.into());
|
|
1885
1372
|
}
|
|
1886
1373
|
|
|
1887
|
-
assert_token_program(token_program)?;
|
|
1888
|
-
|
|
1889
1374
|
// Load and update recipient claim
|
|
1890
1375
|
let mut claim_data = recipient_claim_account.try_borrow_mut_data()?;
|
|
1891
1376
|
let mut claim_state: RecipientClaim = BorshDeserialize::deserialize(&mut &claim_data[8..])?;
|
|
@@ -1898,10 +1383,8 @@ fn process_distribute_claimable_funds(
|
|
|
1898
1383
|
claim_state.amount = 0;
|
|
1899
1384
|
claim_state.timestamp = 0;
|
|
1900
1385
|
|
|
1901
|
-
assert_token_account(recipient_usdc, &recipient, &mailer_state.usdc_mint)?;
|
|
1902
|
-
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
1903
|
-
|
|
1904
1386
|
// Transfer USDC from mailer to recipient
|
|
1387
|
+
let (mailer_pda, bump) = Pubkey::find_program_address(&[b"mailer"], _program_id);
|
|
1905
1388
|
invoke_signed(
|
|
1906
1389
|
&spl_token::instruction::transfer(
|
|
1907
1390
|
token_program.key,
|
|
@@ -1911,118 +1394,16 @@ fn process_distribute_claimable_funds(
|
|
|
1911
1394
|
&[],
|
|
1912
1395
|
amount,
|
|
1913
1396
|
)?,
|
|
1914
|
-
&[
|
|
1915
|
-
|
|
1916
|
-
recipient_usdc.clone(),
|
|
1917
|
-
mailer_account.clone(),
|
|
1918
|
-
token_program.clone(),
|
|
1919
|
-
],
|
|
1920
|
-
&[&[b"mailer", &[mailer_state.bump]]],
|
|
1397
|
+
&[mailer_usdc.clone(), recipient_usdc.clone(), token_program.clone()],
|
|
1398
|
+
&[&[b"mailer", &[bump]]],
|
|
1921
1399
|
)?;
|
|
1922
1400
|
|
|
1923
1401
|
claim_state.serialize(&mut &mut claim_data[8..])?;
|
|
1924
|
-
|
|
1402
|
+
|
|
1925
1403
|
msg!("Distributed claimable funds to {}: {}", recipient, amount);
|
|
1926
1404
|
Ok(())
|
|
1927
1405
|
}
|
|
1928
1406
|
|
|
1929
|
-
/// Claim expired shares and move them under owner control (owner only)
|
|
1930
|
-
fn process_claim_expired_shares(
|
|
1931
|
-
program_id: &Pubkey,
|
|
1932
|
-
accounts: &[AccountInfo],
|
|
1933
|
-
recipient: Pubkey,
|
|
1934
|
-
) -> ProgramResult {
|
|
1935
|
-
let account_iter = &mut accounts.iter();
|
|
1936
|
-
let owner = next_account_info(account_iter)?;
|
|
1937
|
-
let mailer_account = next_account_info(account_iter)?;
|
|
1938
|
-
let recipient_claim_account = next_account_info(account_iter)?;
|
|
1939
|
-
|
|
1940
|
-
if !owner.is_signer {
|
|
1941
|
-
return Err(ProgramError::MissingRequiredSignature);
|
|
1942
|
-
}
|
|
1943
|
-
|
|
1944
|
-
let (_mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
1945
|
-
|
|
1946
|
-
// Load and verify mailer state
|
|
1947
|
-
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1948
|
-
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
1949
|
-
|
|
1950
|
-
if mailer_state.owner != *owner.key {
|
|
1951
|
-
return Err(MailerError::OnlyOwner.into());
|
|
1952
|
-
}
|
|
1953
|
-
|
|
1954
|
-
// Verify recipient claim PDA
|
|
1955
|
-
let (claim_pda, _) = Pubkey::find_program_address(&[b"claim", recipient.as_ref()], program_id);
|
|
1956
|
-
if recipient_claim_account.key != &claim_pda {
|
|
1957
|
-
return Err(MailerError::InvalidPDA.into());
|
|
1958
|
-
}
|
|
1959
|
-
|
|
1960
|
-
// Load and validate claim state
|
|
1961
|
-
let mut claim_data = recipient_claim_account.try_borrow_mut_data()?;
|
|
1962
|
-
let mut claim_state: RecipientClaim = BorshDeserialize::deserialize(&mut &claim_data[8..])?;
|
|
1963
|
-
|
|
1964
|
-
if claim_state.recipient != recipient {
|
|
1965
|
-
return Err(MailerError::InvalidRecipient.into());
|
|
1966
|
-
}
|
|
1967
|
-
if claim_state.amount == 0 {
|
|
1968
|
-
return Err(MailerError::NoClaimableAmount.into());
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
|
-
let current_time = Clock::get()?.unix_timestamp;
|
|
1972
|
-
if current_time <= claim_state.timestamp + CLAIM_PERIOD {
|
|
1973
|
-
return Err(MailerError::ClaimPeriodNotExpired.into());
|
|
1974
|
-
}
|
|
1975
|
-
|
|
1976
|
-
let amount = claim_state.amount;
|
|
1977
|
-
claim_state.amount = 0;
|
|
1978
|
-
claim_state.timestamp = 0;
|
|
1979
|
-
claim_state.serialize(&mut &mut claim_data[8..])?;
|
|
1980
|
-
drop(claim_data);
|
|
1981
|
-
|
|
1982
|
-
mailer_state.owner_claimable += amount;
|
|
1983
|
-
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
1984
|
-
|
|
1985
|
-
msg!("Expired shares claimed for {}: {}", recipient, amount);
|
|
1986
|
-
Ok(())
|
|
1987
|
-
}
|
|
1988
|
-
|
|
1989
|
-
/// Emergency unpause without fund distribution (owner only)
|
|
1990
|
-
fn process_emergency_unpause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
|
|
1991
|
-
let account_iter = &mut accounts.iter();
|
|
1992
|
-
let owner = next_account_info(account_iter)?;
|
|
1993
|
-
let mailer_account = next_account_info(account_iter)?;
|
|
1994
|
-
|
|
1995
|
-
if !owner.is_signer {
|
|
1996
|
-
return Err(ProgramError::MissingRequiredSignature);
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
|
-
assert_mailer_account(_program_id, mailer_account)?;
|
|
2000
|
-
|
|
2001
|
-
// Load and update mailer state
|
|
2002
|
-
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
2003
|
-
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
2004
|
-
|
|
2005
|
-
// Verify owner
|
|
2006
|
-
if mailer_state.owner != *owner.key {
|
|
2007
|
-
return Err(MailerError::OnlyOwner.into());
|
|
2008
|
-
}
|
|
2009
|
-
|
|
2010
|
-
// Check if not paused
|
|
2011
|
-
if !mailer_state.paused {
|
|
2012
|
-
return Err(MailerError::ContractNotPaused.into());
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
// Set unpaused state without fund distribution
|
|
2016
|
-
mailer_state.paused = false;
|
|
2017
|
-
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
2018
|
-
|
|
2019
|
-
msg!(
|
|
2020
|
-
"Contract emergency unpaused by owner: {} - funds can be claimed manually",
|
|
2021
|
-
owner.key
|
|
2022
|
-
);
|
|
2023
|
-
Ok(())
|
|
2024
|
-
}
|
|
2025
|
-
|
|
2026
1407
|
/// Simple hash function for account discriminators
|
|
2027
1408
|
fn hash_discriminator(name: &str) -> u64 {
|
|
2028
1409
|
use std::collections::hash_map::DefaultHasher;
|