@sudobility/contracts 1.10.1 → 1.11.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 +67 -2
- package/artifacts/contracts/Mailer.sol/Mailer.dbg.json +1 -1
- package/artifacts/contracts/Mailer.sol/Mailer.json +67 -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/typechain-types/Mailer.d.ts +50 -2
- package/dist/evm/typechain-types/Mailer.d.ts.map +1 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.d.ts +53 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.js +66 -1
- package/dist/evm/typechain-types/factories/Mailer__factory.js.map +1 -1
- package/dist/unified/typechain-types/Mailer.d.ts +50 -2
- package/dist/unified/typechain-types/Mailer.d.ts.map +1 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.d.ts +53 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.d.ts.map +1 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.js +66 -1
- package/dist/unified/typechain-types/factories/Mailer__factory.js.map +1 -1
- package/dist/unified-esm/typechain-types/Mailer.d.ts +50 -2
- package/dist/unified-esm/typechain-types/Mailer.d.ts.map +1 -1
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.d.ts +53 -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 +66 -1
- package/dist/unified-esm/typechain-types/factories/Mailer__factory.js.map +1 -1
- package/package.json +6 -1
- package/programs/mailer/src/lib.rs +305 -13
- package/programs/mailer/tests/integration_tests.rs +206 -3
- package/typechain-types/Mailer.ts +79 -0
- package/typechain-types/factories/Mailer__factory.ts +66 -1
|
@@ -33,11 +33,13 @@ use solana_program::{
|
|
|
33
33
|
msg,
|
|
34
34
|
program::{invoke, invoke_signed},
|
|
35
35
|
program_error::ProgramError,
|
|
36
|
+
program_pack::Pack,
|
|
36
37
|
pubkey::Pubkey,
|
|
37
38
|
rent::Rent,
|
|
38
39
|
system_instruction,
|
|
39
40
|
sysvar::Sysvar,
|
|
40
41
|
};
|
|
42
|
+
use spl_token::state::Account as TokenAccount;
|
|
41
43
|
use thiserror::Error;
|
|
42
44
|
|
|
43
45
|
// Program ID for the Native Mailer program
|
|
@@ -177,6 +179,22 @@ pub enum MailerInstruction {
|
|
|
177
179
|
/// 4. `[]` Token program
|
|
178
180
|
SendPreparedToEmail { to_email: String, mail_id: String },
|
|
179
181
|
|
|
182
|
+
/// Send message through webhook (referenced by webhookId)
|
|
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,
|
|
196
|
+
},
|
|
197
|
+
|
|
180
198
|
/// Claim recipient share
|
|
181
199
|
/// Accounts:
|
|
182
200
|
/// 0. `[signer]` Recipient
|
|
@@ -310,6 +328,10 @@ pub enum MailerError {
|
|
|
310
328
|
InvalidPDA,
|
|
311
329
|
#[error("Invalid account owner")]
|
|
312
330
|
InvalidAccountOwner,
|
|
331
|
+
#[error("Invalid token mint")]
|
|
332
|
+
InvalidMint,
|
|
333
|
+
#[error("Invalid token program")]
|
|
334
|
+
InvalidTokenProgram,
|
|
313
335
|
#[error("Contract is paused")]
|
|
314
336
|
ContractPaused,
|
|
315
337
|
#[error("Contract is not paused")]
|
|
@@ -372,6 +394,19 @@ pub fn process_instruction(
|
|
|
372
394
|
MailerInstruction::SendPreparedToEmail { to_email, mail_id } => {
|
|
373
395
|
process_send_prepared_to_email(program_id, accounts, to_email, mail_id)
|
|
374
396
|
}
|
|
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
|
+
),
|
|
375
410
|
MailerInstruction::ClaimRecipientShare => {
|
|
376
411
|
process_claim_recipient_share(program_id, accounts)
|
|
377
412
|
}
|
|
@@ -489,15 +524,15 @@ fn process_send(
|
|
|
489
524
|
}
|
|
490
525
|
|
|
491
526
|
// Load mailer state
|
|
492
|
-
let (mailer_pda, _) =
|
|
493
|
-
if mailer_account.key != &mailer_pda {
|
|
494
|
-
return Err(MailerError::InvalidPDA.into());
|
|
495
|
-
}
|
|
496
|
-
|
|
527
|
+
let (mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
497
528
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
498
529
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
499
530
|
drop(mailer_data);
|
|
500
531
|
|
|
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
|
+
|
|
501
536
|
// Check if contract is paused
|
|
502
537
|
if mailer_state.paused {
|
|
503
538
|
return Err(MailerError::ContractPaused.into());
|
|
@@ -646,10 +681,15 @@ fn process_send_prepared(
|
|
|
646
681
|
}
|
|
647
682
|
|
|
648
683
|
// Load mailer state
|
|
684
|
+
let (mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
649
685
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
650
686
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
651
687
|
drop(mailer_data);
|
|
652
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
|
+
|
|
653
693
|
// Check if contract is paused
|
|
654
694
|
if mailer_state.paused {
|
|
655
695
|
return Err(MailerError::ContractPaused.into());
|
|
@@ -795,10 +835,15 @@ fn process_send_to_email(
|
|
|
795
835
|
}
|
|
796
836
|
|
|
797
837
|
// Load mailer state
|
|
838
|
+
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
798
839
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
799
840
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
800
841
|
drop(mailer_data);
|
|
801
842
|
|
|
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
|
+
|
|
802
847
|
// Check if contract is paused
|
|
803
848
|
if mailer_state.paused {
|
|
804
849
|
return Err(MailerError::ContractPaused.into());
|
|
@@ -869,10 +914,15 @@ fn process_send_prepared_to_email(
|
|
|
869
914
|
}
|
|
870
915
|
|
|
871
916
|
// Load mailer state
|
|
917
|
+
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
872
918
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
873
919
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
874
920
|
drop(mailer_data);
|
|
875
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
|
+
|
|
876
926
|
// Check if contract is paused
|
|
877
927
|
if mailer_state.paused {
|
|
878
928
|
return Err(MailerError::ContractPaused.into());
|
|
@@ -924,6 +974,163 @@ fn process_send_prepared_to_email(
|
|
|
924
974
|
Ok(())
|
|
925
975
|
}
|
|
926
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
|
+
)?;
|
|
1085
|
+
|
|
1086
|
+
// Record revenue shares (only if fee > 0)
|
|
1087
|
+
record_shares(recipient_claim, mailer_account, to, effective_fee)?;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
msg!("Webhook mail sent from {} to {} (webhookId: {}, revenue share enabled, resolve sender: {}, effective fee: {})", sender.key, to, webhook_id, _resolve_sender_to_name, effective_fee);
|
|
1091
|
+
} else {
|
|
1092
|
+
// Standard mode: 10% fee only, no revenue sharing
|
|
1093
|
+
let owner_fee = (effective_fee * 10) / 100; // 10% of effective fee
|
|
1094
|
+
|
|
1095
|
+
// Transfer only owner fee (10%)
|
|
1096
|
+
if owner_fee > 0 {
|
|
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
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// Update owner claimable
|
|
1116
|
+
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
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..])?;
|
|
1120
|
+
|
|
1121
|
+
msg!(
|
|
1122
|
+
"Webhook mail sent from {} to {} (webhookId: {}, resolve sender: {}, effective fee: {})",
|
|
1123
|
+
sender.key,
|
|
1124
|
+
to,
|
|
1125
|
+
webhook_id,
|
|
1126
|
+
_resolve_sender_to_name,
|
|
1127
|
+
effective_fee
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
Ok(())
|
|
1132
|
+
}
|
|
1133
|
+
|
|
927
1134
|
/// Process claim recipient share
|
|
928
1135
|
fn process_claim_recipient_share(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
|
|
929
1136
|
let account_iter = &mut accounts.iter();
|
|
@@ -938,6 +1145,13 @@ fn process_claim_recipient_share(_program_id: &Pubkey, accounts: &[AccountInfo])
|
|
|
938
1145
|
return Err(ProgramError::MissingRequiredSignature);
|
|
939
1146
|
}
|
|
940
1147
|
|
|
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
|
+
|
|
941
1155
|
// Load claim state
|
|
942
1156
|
let mut claim_data = recipient_claim.try_borrow_mut_data()?;
|
|
943
1157
|
let mut claim_state: RecipientClaim = BorshDeserialize::deserialize(&mut &claim_data[8..])?;
|
|
@@ -964,6 +1178,11 @@ fn process_claim_recipient_share(_program_id: &Pubkey, accounts: &[AccountInfo])
|
|
|
964
1178
|
// Load mailer state for PDA signing
|
|
965
1179
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
966
1180
|
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)?;
|
|
967
1186
|
|
|
968
1187
|
// Transfer USDC from mailer to recipient
|
|
969
1188
|
invoke_signed(
|
|
@@ -1001,6 +1220,8 @@ fn process_claim_owner_share(_program_id: &Pubkey, accounts: &[AccountInfo]) ->
|
|
|
1001
1220
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1002
1221
|
}
|
|
1003
1222
|
|
|
1223
|
+
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
1224
|
+
|
|
1004
1225
|
// Load and update mailer state
|
|
1005
1226
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1006
1227
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1018,6 +1239,10 @@ fn process_claim_owner_share(_program_id: &Pubkey, accounts: &[AccountInfo]) ->
|
|
|
1018
1239
|
mailer_state.serialize(&mut &mut mailer_data[8..])?;
|
|
1019
1240
|
drop(mailer_data);
|
|
1020
1241
|
|
|
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
|
+
|
|
1021
1246
|
// Transfer USDC from mailer to owner
|
|
1022
1247
|
invoke_signed(
|
|
1023
1248
|
&spl_token::instruction::transfer(
|
|
@@ -1051,6 +1276,8 @@ fn process_set_fee(_program_id: &Pubkey, accounts: &[AccountInfo], new_fee: u64)
|
|
|
1051
1276
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1052
1277
|
}
|
|
1053
1278
|
|
|
1279
|
+
assert_mailer_account(_program_id, mailer_account)?;
|
|
1280
|
+
|
|
1054
1281
|
// Load and update mailer state
|
|
1055
1282
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1056
1283
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1091,11 +1318,17 @@ fn process_delegate_to(
|
|
|
1091
1318
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1092
1319
|
}
|
|
1093
1320
|
|
|
1321
|
+
let (mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
1322
|
+
|
|
1094
1323
|
// Load mailer state
|
|
1095
1324
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1096
1325
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
1097
1326
|
drop(mailer_data);
|
|
1098
1327
|
|
|
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
|
+
|
|
1099
1332
|
// Check if contract is paused
|
|
1100
1333
|
if mailer_state.paused {
|
|
1101
1334
|
return Err(MailerError::ContractPaused.into());
|
|
@@ -1191,10 +1424,7 @@ fn process_reject_delegation(program_id: &Pubkey, accounts: &[AccountInfo]) -> P
|
|
|
1191
1424
|
}
|
|
1192
1425
|
|
|
1193
1426
|
// Verify mailer state PDA and ensure contract is not paused
|
|
1194
|
-
let (
|
|
1195
|
-
if mailer_account.key != &mailer_pda {
|
|
1196
|
-
return Err(MailerError::InvalidPDA.into());
|
|
1197
|
-
}
|
|
1427
|
+
let (_mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
1198
1428
|
|
|
1199
1429
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1200
1430
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1235,6 +1465,8 @@ fn process_set_delegation_fee(
|
|
|
1235
1465
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1236
1466
|
}
|
|
1237
1467
|
|
|
1468
|
+
assert_mailer_account(_program_id, mailer_account)?;
|
|
1469
|
+
|
|
1238
1470
|
// Load and update mailer state
|
|
1239
1471
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1240
1472
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1275,6 +1507,8 @@ fn process_set_custom_fee_percentage(
|
|
|
1275
1507
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1276
1508
|
}
|
|
1277
1509
|
|
|
1510
|
+
assert_mailer_account(program_id, mailer_account)?;
|
|
1511
|
+
|
|
1278
1512
|
// Load mailer state and verify owner
|
|
1279
1513
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1280
1514
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1364,6 +1598,8 @@ fn process_clear_custom_fee_percentage(
|
|
|
1364
1598
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1365
1599
|
}
|
|
1366
1600
|
|
|
1601
|
+
assert_mailer_account(program_id, mailer_account)?;
|
|
1602
|
+
|
|
1367
1603
|
// Load mailer state and verify owner
|
|
1368
1604
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1369
1605
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1402,6 +1638,44 @@ fn process_clear_custom_fee_percentage(
|
|
|
1402
1638
|
Ok(())
|
|
1403
1639
|
}
|
|
1404
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
|
+
|
|
1665
|
+
Ok(())
|
|
1666
|
+
}
|
|
1667
|
+
|
|
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
|
+
|
|
1405
1679
|
/// Record revenue shares for priority messages
|
|
1406
1680
|
fn record_shares(
|
|
1407
1681
|
recipient_claim: &AccountInfo,
|
|
@@ -1486,6 +1760,8 @@ fn process_pause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResul
|
|
|
1486
1760
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1487
1761
|
}
|
|
1488
1762
|
|
|
1763
|
+
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
1764
|
+
|
|
1489
1765
|
// Load and update mailer state
|
|
1490
1766
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1491
1767
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1503,13 +1779,17 @@ fn process_pause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResul
|
|
|
1503
1779
|
// Set paused state
|
|
1504
1780
|
mailer_state.paused = true;
|
|
1505
1781
|
|
|
1782
|
+
assert_token_program(token_program)?;
|
|
1783
|
+
|
|
1506
1784
|
// Distribute owner claimable funds if any
|
|
1507
1785
|
if mailer_state.owner_claimable > 0 {
|
|
1508
1786
|
let amount = mailer_state.owner_claimable;
|
|
1509
1787
|
mailer_state.owner_claimable = 0;
|
|
1510
1788
|
|
|
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
|
+
|
|
1511
1792
|
// Transfer USDC from mailer to owner
|
|
1512
|
-
let (mailer_pda, bump) = Pubkey::find_program_address(&[b"mailer"], _program_id);
|
|
1513
1793
|
invoke_signed(
|
|
1514
1794
|
&spl_token::instruction::transfer(
|
|
1515
1795
|
token_program.key,
|
|
@@ -1525,7 +1805,7 @@ fn process_pause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResul
|
|
|
1525
1805
|
mailer_account.clone(),
|
|
1526
1806
|
token_program.clone(),
|
|
1527
1807
|
],
|
|
1528
|
-
&[&[b"mailer", &[bump]]],
|
|
1808
|
+
&[&[b"mailer", &[mailer_state.bump]]],
|
|
1529
1809
|
)?;
|
|
1530
1810
|
|
|
1531
1811
|
msg!("Distributed owner funds during pause: {}", amount);
|
|
@@ -1548,6 +1828,8 @@ fn process_unpause(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramRes
|
|
|
1548
1828
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1549
1829
|
}
|
|
1550
1830
|
|
|
1831
|
+
assert_mailer_account(_program_id, mailer_account)?;
|
|
1832
|
+
|
|
1551
1833
|
// Load and update mailer state
|
|
1552
1834
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1553
1835
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1584,6 +1866,8 @@ fn process_distribute_claimable_funds(
|
|
|
1584
1866
|
let mailer_usdc = next_account_info(account_iter)?;
|
|
1585
1867
|
let token_program = next_account_info(account_iter)?;
|
|
1586
1868
|
|
|
1869
|
+
let (mailer_pda, _) = assert_mailer_account(_program_id, mailer_account)?;
|
|
1870
|
+
|
|
1587
1871
|
// Load mailer state to check if paused
|
|
1588
1872
|
let mailer_data = mailer_account.try_borrow_data()?;
|
|
1589
1873
|
let mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1600,6 +1884,8 @@ fn process_distribute_claimable_funds(
|
|
|
1600
1884
|
return Err(MailerError::InvalidPDA.into());
|
|
1601
1885
|
}
|
|
1602
1886
|
|
|
1887
|
+
assert_token_program(token_program)?;
|
|
1888
|
+
|
|
1603
1889
|
// Load and update recipient claim
|
|
1604
1890
|
let mut claim_data = recipient_claim_account.try_borrow_mut_data()?;
|
|
1605
1891
|
let mut claim_state: RecipientClaim = BorshDeserialize::deserialize(&mut &claim_data[8..])?;
|
|
@@ -1612,8 +1898,10 @@ fn process_distribute_claimable_funds(
|
|
|
1612
1898
|
claim_state.amount = 0;
|
|
1613
1899
|
claim_state.timestamp = 0;
|
|
1614
1900
|
|
|
1901
|
+
assert_token_account(recipient_usdc, &recipient, &mailer_state.usdc_mint)?;
|
|
1902
|
+
assert_token_account(mailer_usdc, &mailer_pda, &mailer_state.usdc_mint)?;
|
|
1903
|
+
|
|
1615
1904
|
// Transfer USDC from mailer to recipient
|
|
1616
|
-
let (mailer_pda, bump) = Pubkey::find_program_address(&[b"mailer"], _program_id);
|
|
1617
1905
|
invoke_signed(
|
|
1618
1906
|
&spl_token::instruction::transfer(
|
|
1619
1907
|
token_program.key,
|
|
@@ -1629,7 +1917,7 @@ fn process_distribute_claimable_funds(
|
|
|
1629
1917
|
mailer_account.clone(),
|
|
1630
1918
|
token_program.clone(),
|
|
1631
1919
|
],
|
|
1632
|
-
&[&[b"mailer", &[bump]]],
|
|
1920
|
+
&[&[b"mailer", &[mailer_state.bump]]],
|
|
1633
1921
|
)?;
|
|
1634
1922
|
|
|
1635
1923
|
claim_state.serialize(&mut &mut claim_data[8..])?;
|
|
@@ -1653,6 +1941,8 @@ fn process_claim_expired_shares(
|
|
|
1653
1941
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1654
1942
|
}
|
|
1655
1943
|
|
|
1944
|
+
let (_mailer_pda, _) = assert_mailer_account(program_id, mailer_account)?;
|
|
1945
|
+
|
|
1656
1946
|
// Load and verify mailer state
|
|
1657
1947
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1658
1948
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|
|
@@ -1706,6 +1996,8 @@ fn process_emergency_unpause(_program_id: &Pubkey, accounts: &[AccountInfo]) ->
|
|
|
1706
1996
|
return Err(ProgramError::MissingRequiredSignature);
|
|
1707
1997
|
}
|
|
1708
1998
|
|
|
1999
|
+
assert_mailer_account(_program_id, mailer_account)?;
|
|
2000
|
+
|
|
1709
2001
|
// Load and update mailer state
|
|
1710
2002
|
let mut mailer_data = mailer_account.try_borrow_mut_data()?;
|
|
1711
2003
|
let mut mailer_state: MailerState = BorshDeserialize::deserialize(&mut &mailer_data[8..])?;
|