1mod transfer;
86mod utils;
87
88pub mod error;
89pub mod state;
90
91use anchor_lang::prelude::*;
92use anchor_spl::token::{Mint, Token, TokenAccount};
93
94use crate::{
95 error::StreamError,
96 state::Stream,
97 transfer::{transfer_from_escrow, transfer_to_escrow},
98 utils::is_token_account_rent_exempt,
99};
100
101declare_id!("4WLNkJ6RKt54sv85iTgJPLgoaxfrxAasZWBxAPLUfuVG");
102
103pub const STREAM_ACCOUNT_SEED: &[u8] = b"stream";
105
106#[program]
107pub mod superstream {
108 use super::*;
111
112 pub fn create_prepaid(
118 mut ctx: Context<Create>,
119 seed: u64,
120 name: String,
121 recipient: Pubkey,
122 starts_at: u64,
123 ends_at: u64,
124 initial_amount: u64,
125 flow_interval: u64,
126 flow_rate: u64,
127 sender_can_cancel: bool,
128 sender_can_cancel_at: u64,
129 sender_can_change_sender: bool,
130 sender_can_change_sender_at: u64,
131 sender_can_pause: bool,
132 sender_can_pause_at: u64,
133 recipient_can_resume_pause_by_sender: bool,
134 recipient_can_resume_pause_by_sender_at: u64,
135 anyone_can_withdraw_for_recipient: bool,
136 anyone_can_withdraw_for_recipient_at: u64,
137 ) -> Result<()> {
138 create(
139 &mut ctx,
140 true,
141 recipient,
142 name,
143 starts_at,
144 ends_at,
145 initial_amount,
146 flow_interval,
147 flow_rate,
148 sender_can_cancel,
149 sender_can_cancel_at,
150 sender_can_change_sender,
151 sender_can_change_sender_at,
152 sender_can_pause,
153 sender_can_pause_at,
154 recipient_can_resume_pause_by_sender,
155 recipient_can_resume_pause_by_sender_at,
156 anyone_can_withdraw_for_recipient,
157 anyone_can_withdraw_for_recipient_at,
158 seed,
159 )?;
160
161 let stream = &mut ctx.accounts.stream;
162 let prepaid_amount_needed = stream.initialize_prepaid()?;
163 ctx.accounts.transfer_to_escrow(prepaid_amount_needed)
164 }
165
166 pub fn create_non_prepaid(
175 mut ctx: Context<Create>,
176 seed: u64,
177 name: String,
178 recipient: Pubkey,
179 starts_at: u64,
180 ends_at: u64,
181 initial_amount: u64,
182 flow_interval: u64,
183 flow_rate: u64,
184 sender_can_cancel: bool,
185 sender_can_cancel_at: u64,
186 sender_can_change_sender: bool,
187 sender_can_change_sender_at: u64,
188 sender_can_pause: bool,
189 sender_can_pause_at: u64,
190 recipient_can_resume_pause_by_sender: bool,
191 recipient_can_resume_pause_by_sender_at: u64,
192 anyone_can_withdraw_for_recipient: bool,
193 anyone_can_withdraw_for_recipient_at: u64,
194 topup_amount: u64,
195 ) -> Result<()> {
196 create(
197 &mut ctx,
198 false,
199 recipient,
200 name,
201 starts_at,
202 ends_at,
203 initial_amount,
204 flow_interval,
205 flow_rate,
206 sender_can_cancel,
207 sender_can_cancel_at,
208 sender_can_change_sender,
209 sender_can_change_sender_at,
210 sender_can_pause,
211 sender_can_pause_at,
212 recipient_can_resume_pause_by_sender,
213 recipient_can_resume_pause_by_sender_at,
214 anyone_can_withdraw_for_recipient,
215 anyone_can_withdraw_for_recipient_at,
216 seed,
217 )?;
218
219 let stream = &mut ctx.accounts.stream;
220 stream.initialize_non_prepaid(topup_amount)?;
221 ctx.accounts.transfer_to_escrow(topup_amount)
222 }
223
224 pub fn cancel(ctx: Context<Cancel>, seed: u64, name: String, recipient: Pubkey) -> Result<()> {
230 let stream = &mut ctx.accounts.stream;
231 let stream_key = stream.to_account_info().key;
232 let bump = stream.bump;
233 let params = stream.cancel(*stream_key, &ctx.accounts.signer, recipient)?;
234 ctx.accounts
235 .transfer_from_escrow_to_sender(seed, &name, bump, params.transfer_amount_sender)?;
236 ctx.accounts
237 .transfer_from_escrow_to_signer(seed, &name, bump, params.transfer_amount_signer)?;
238 ctx.accounts
239 .transfer_from_escrow_to_recipient(seed, &name, bump, params.transfer_amount_recipient)?;
240
241 Ok(())
242 }
243
244 pub fn withdraw_excess_topup_non_prepaid_ended(
250 ctx: Context<WithdrawExcessTopupNonPrepaidEnded>,
251 seed: u64,
252 name: String,
253 ) -> Result<()> {
254 let stream = &mut ctx.accounts.stream;
255 let amount = stream.withdraw_excess_topup_non_prepaid_ended()?;
256 if amount > 0 {
257 let bump = stream.bump;
258 ctx.accounts.transfer_from_escrow(seed, &name, bump, amount)?;
259 }
260 Ok(())
261 }
262
263 pub fn topup_non_prepaid(
271 ctx: Context<TopupNonPrepaid>,
272 _seed: u64,
273 _name: String,
274 topup_amount: u64,
275 ) -> Result<()> {
276 let stream = &mut ctx.accounts.stream;
277 stream.topup_non_prepaid(topup_amount)?;
278 ctx.accounts.transfer_to_escrow(topup_amount)
279 }
280
281 pub fn change_sender_non_prepaid(
289 ctx: Context<ChangeSenderNonPrepaid>,
290 _seed: u64,
291 _name: String,
292 new_sender: Pubkey,
293 ) -> Result<()> {
294 let stream = &mut ctx.accounts.stream;
295 stream.change_sender_non_prepaid(&ctx.accounts.sender, new_sender)
296 }
297
298 pub fn withdraw(
304 ctx: Context<WithdrawAndChangeRecipient>,
305 seed: u64,
306 name: String,
307 recipient: Pubkey,
308 ) -> Result<()> {
309 withdraw_and_change_recipient(ctx, seed, name, recipient, Pubkey::default())
310 }
311
312 pub fn withdraw_and_change_recipient(
320 ctx: Context<WithdrawAndChangeRecipient>,
321 seed: u64,
322 name: String,
323 recipient: Pubkey,
324 new_recipient: Pubkey,
325 ) -> Result<()> {
326 let stream = &mut ctx.accounts.stream;
327 let amount_available_to_withdraw =
328 stream.withdraw_and_change_recipient(&ctx.accounts.signer, recipient, new_recipient)?;
329 let bump = stream.bump;
330 ctx.accounts
331 .transfer_from_escrow(seed, &name, bump, amount_available_to_withdraw)
332 }
333
334 pub fn pause_non_prepaid(ctx: Context<PauseNonPrepaid>, _seed: u64, _name: String) -> Result<()> {
340 let stream = &mut ctx.accounts.stream;
341 stream.pause_non_prepaid(&ctx.accounts.signer)
342 }
343
344 pub fn resume_non_prepaid(ctx: Context<ResumeNonPrepaid>, _seed: u64, _name: String) -> Result<()> {
350 let stream = &mut ctx.accounts.stream;
351 stream.resume_non_prepaid(&ctx.accounts.signer)
352 }
353}
354
355pub(crate) fn create(
356 ctx: &mut Context<Create>,
357 is_prepaid: bool,
358 recipient: Pubkey,
359 name: String,
360 starts_at: u64,
361 ends_at: u64,
362 initial_amount: u64,
363 flow_interval: u64,
364 flow_rate: u64,
365 sender_can_cancel: bool,
366 sender_can_cancel_at: u64,
367 sender_can_change_sender: bool,
368 sender_can_change_sender_at: u64,
369 sender_can_pause: bool,
370 sender_can_pause_at: u64,
371 recipient_can_resume_pause_by_sender: bool,
372 recipient_can_resume_pause_by_sender_at: u64,
373 anyone_can_withdraw_for_recipient: bool,
374 anyone_can_withdraw_for_recipient_at: u64,
375 seed: u64,
376) -> Result<()> {
377 let escrow_token_account = &ctx.accounts.escrow_token;
378 require!(
379 is_token_account_rent_exempt(escrow_token_account)?,
380 StreamError::EscrowNotRentExempt,
381 );
382
383 let stream = &mut ctx.accounts.stream;
384 stream.initialize(
385 is_prepaid,
386 ctx.accounts.mint.key(),
387 ctx.accounts.sender.key(),
388 recipient,
389 name,
390 starts_at,
391 ends_at,
392 initial_amount,
393 flow_interval,
394 flow_rate,
395 sender_can_cancel,
396 sender_can_cancel_at,
397 sender_can_change_sender,
398 sender_can_change_sender_at,
399 sender_can_pause,
400 sender_can_pause_at,
401 recipient_can_resume_pause_by_sender,
402 recipient_can_resume_pause_by_sender_at,
403 anyone_can_withdraw_for_recipient,
404 anyone_can_withdraw_for_recipient_at,
405 seed,
406 *ctx.bumps.get("stream").unwrap(),
407 )
408}
409
410#[derive(Accounts)]
412#[instruction(seed: u64, name: String)]
413pub struct Create<'info> {
414 #[account(
416 init,
417 seeds = [
418 STREAM_ACCOUNT_SEED,
419 seed.to_le_bytes().as_ref(),
420 mint.key().as_ref(),
421 name.as_bytes(),
422 ],
423 payer = sender,
424 space = Stream::space(&name),
425 bump,
426 )]
427 pub stream: Account<'info, Stream>,
428
429 #[account(mut)]
431 pub sender: Signer<'info>,
432 pub mint: Box<Account<'info, Mint>>,
434
435 #[account(
437 mut,
438 constraint =
439 sender_token.mint == mint.key()
440 && sender_token.owner == sender.key(),
441 )]
442 pub sender_token: Box<Account<'info, TokenAccount>>,
443 #[account(
445 mut,
446 constraint =
447 escrow_token.mint == mint.key()
448 && escrow_token.owner == stream.key(),
449 )]
450 pub escrow_token: Box<Account<'info, TokenAccount>>,
451
452 pub token_program: Program<'info, Token>,
454 pub system_program: Program<'info, System>,
456}
457
458#[derive(Accounts)]
460#[instruction(seed: u64, name: String, recipient: Pubkey)]
461pub struct Cancel<'info> {
462 #[account(
464 mut,
465 seeds = [
466 STREAM_ACCOUNT_SEED,
467 seed.to_le_bytes().as_ref(),
468 mint.key().as_ref(),
469 name.as_bytes(),
470 ],
471 bump,
472 )]
473 pub stream: Account<'info, Stream>,
474
475 pub signer: Signer<'info>,
478
479 #[account(constraint = sender.key() == stream.sender)]
484 pub sender: UncheckedAccount<'info>,
485 pub mint: Box<Account<'info, Mint>>,
487
488 #[account(
490 mut,
491 constraint =
492 signer_token.mint == mint.key()
493 && signer_token.owner == signer.key(),
494 )]
495 pub signer_token: Box<Account<'info, TokenAccount>>,
496 #[account(
498 mut,
499 constraint =
500 sender_token.mint == mint.key()
501 && sender_token.owner == sender.key(),
502 )]
503 pub sender_token: Box<Account<'info, TokenAccount>>,
504 #[account(
506 mut,
507 constraint =
508 recipient_token.mint == mint.key()
509 && recipient_token.owner == recipient,
510 )]
511 pub recipient_token: Box<Account<'info, TokenAccount>>,
512 #[account(
514 mut,
515 constraint =
516 escrow_token.mint == mint.key()
517 && escrow_token.owner == stream.key(),
518 )]
519 pub escrow_token: Box<Account<'info, TokenAccount>>,
520
521 pub token_program: Program<'info, Token>,
523}
524
525#[derive(Accounts)]
527#[instruction(seed: u64, name: String)]
528pub struct WithdrawExcessTopupNonPrepaidEnded<'info> {
529 #[account(
531 mut,
532 seeds = [
533 STREAM_ACCOUNT_SEED,
534 seed.to_le_bytes().as_ref(),
535 mint.key().as_ref(),
536 name.as_bytes(),
537 ],
538 bump,
539 )]
540 pub stream: Account<'info, Stream>,
541
542 pub signer: Signer<'info>,
544
545 #[account(constraint = sender.key() == stream.sender)]
550 pub sender: UncheckedAccount<'info>,
551 pub mint: Box<Account<'info, Mint>>,
553
554 #[account(
556 mut,
557 constraint =
558 sender_token.mint == mint.key()
559 && sender_token.owner == sender.key(),
560 )]
561 pub sender_token: Box<Account<'info, TokenAccount>>,
562 #[account(
564 mut,
565 constraint =
566 escrow_token.mint == mint.key()
567 && escrow_token.owner == stream.key(),
568 )]
569 pub escrow_token: Box<Account<'info, TokenAccount>>,
570
571 pub token_program: Program<'info, Token>,
573}
574
575#[derive(Accounts)]
577#[instruction(seed: u64, name: String)]
578pub struct TopupNonPrepaid<'info> {
579 #[account(
581 mut,
582 seeds = [
583 STREAM_ACCOUNT_SEED,
584 seed.to_le_bytes().as_ref(),
585 mint.key().as_ref(),
586 name.as_bytes(),
587 ],
588 bump,
589 )]
590 pub stream: Account<'info, Stream>,
591
592 pub signer: Signer<'info>,
595 pub mint: Account<'info, Mint>,
597
598 #[account(
600 mut,
601 constraint =
602 signer_token.mint == mint.key()
603 && signer_token.owner == signer.key(),
604 )]
605 pub signer_token: Account<'info, TokenAccount>,
606 #[account(
608 mut,
609 constraint =
610 escrow_token.mint == mint.key()
611 && escrow_token.owner == stream.key(),
612 )]
613 pub escrow_token: Account<'info, TokenAccount>,
614
615 pub token_program: Program<'info, Token>,
617}
618
619#[derive(Accounts)]
621#[instruction(seed: u64, name: String)]
622pub struct ChangeSenderNonPrepaid<'info> {
623 #[account(
625 mut,
626 seeds = [
627 STREAM_ACCOUNT_SEED,
628 seed.to_le_bytes().as_ref(),
629 mint.key().as_ref(),
630 name.as_bytes(),
631 ],
632 bump,
633 )]
634 pub stream: Account<'info, Stream>,
635
636 pub sender: Signer<'info>,
638 pub mint: Account<'info, Mint>,
640}
641
642#[derive(Accounts)]
644#[instruction(seed: u64, name: String, recipient: Pubkey)]
645pub struct WithdrawAndChangeRecipient<'info> {
646 #[account(
648 mut,
649 seeds = [
650 STREAM_ACCOUNT_SEED,
651 seed.to_le_bytes().as_ref(),
652 mint.key().as_ref(),
653 name.as_bytes(),
654 ],
655 bump,
656 )]
657 pub stream: Account<'info, Stream>,
658
659 pub signer: Signer<'info>,
664 pub mint: Box<Account<'info, Mint>>,
666
667 #[account(
669 mut,
670 constraint =
671 recipient_token.mint == mint.key()
672 && recipient_token.owner == recipient,
673 )]
674 pub recipient_token: Box<Account<'info, TokenAccount>>,
675 #[account(
677 mut,
678 constraint =
679 escrow_token.mint == mint.key()
680 && escrow_token.owner == stream.key(),
681 )]
682 pub escrow_token: Box<Account<'info, TokenAccount>>,
683
684 pub token_program: Program<'info, Token>,
686}
687
688#[derive(Accounts)]
690#[instruction(seed: u64, name: String)]
691pub struct PauseNonPrepaid<'info> {
692 #[account(
694 mut,
695 seeds = [
696 STREAM_ACCOUNT_SEED,
697 seed.to_le_bytes().as_ref(),
698 mint.key().as_ref(),
699 name.as_bytes(),
700 ],
701 bump,
702 )]
703 pub stream: Account<'info, Stream>,
704
705 pub signer: Signer<'info>,
707 pub mint: Account<'info, Mint>,
709}
710
711#[derive(Accounts)]
713#[instruction(seed: u64, name: String)]
714pub struct ResumeNonPrepaid<'info> {
715 #[account(
717 mut,
718 seeds = [
719 STREAM_ACCOUNT_SEED,
720 seed.to_le_bytes().as_ref(),
721 mint.key().as_ref(),
722 name.as_bytes(),
723 ],
724 bump,
725 )]
726 pub stream: Account<'info, Stream>,
727
728 pub signer: Signer<'info>,
731 pub mint: Account<'info, Mint>,
733}
734
735impl<'info> Create<'info> {
736 pub fn transfer_to_escrow(&self, amount: u64) -> Result<()> {
739 transfer_to_escrow(
740 &self.sender,
741 &self.sender_token,
742 &self.escrow_token,
743 &self.token_program,
744 amount,
745 )
746 }
747}
748
749impl<'info> Cancel<'info> {
750 pub fn transfer_from_escrow_to_sender(&self, seed: u64, name: &str, bump: u8, amount: u64) -> Result<()> {
753 self.transfer_from_escrow(&self.sender_token, seed, name, bump, amount)
754 }
755
756 pub fn transfer_from_escrow_to_signer(&self, seed: u64, name: &str, bump: u8, amount: u64) -> Result<()> {
759 self.transfer_from_escrow(&self.signer_token, seed, name, bump, amount)
760 }
761
762 pub fn transfer_from_escrow_to_recipient(&self, seed: u64, name: &str, bump: u8, amount: u64) -> Result<()> {
765 self.transfer_from_escrow(&self.recipient_token, seed, name, bump, amount)
766 }
767
768 fn transfer_from_escrow(
769 &self,
770 destination_token: &Account<'info, TokenAccount>,
771 seed: u64,
772 name: &str,
773 bump: u8,
774 amount: u64,
775 ) -> Result<()> {
776 transfer_from_escrow(
777 &self.stream,
778 destination_token,
779 &self.escrow_token,
780 &self.token_program,
781 seed,
782 &self.mint.key(),
783 name,
784 bump,
785 amount,
786 )
787 }
788}
789
790impl<'info> WithdrawExcessTopupNonPrepaidEnded<'info> {
791 fn transfer_from_escrow(&self, seed: u64, name: &str, bump: u8, amount: u64) -> Result<()> {
794 transfer_from_escrow(
795 &self.stream,
796 &self.sender_token,
797 &self.escrow_token,
798 &self.token_program,
799 seed,
800 &self.mint.key(),
801 name,
802 bump,
803 amount,
804 )
805 }
806}
807
808impl<'info> TopupNonPrepaid<'info> {
809 pub fn transfer_to_escrow(&self, amount: u64) -> Result<()> {
812 transfer_to_escrow(
813 &self.signer,
814 &self.signer_token,
815 &self.escrow_token,
816 &self.token_program,
817 amount,
818 )
819 }
820}
821
822impl<'info> WithdrawAndChangeRecipient<'info> {
823 pub fn transfer_from_escrow(&self, seed: u64, name: &str, bump: u8, amount: u64) -> Result<()> {
826 transfer_from_escrow(
827 &self.stream,
828 &self.recipient_token,
829 &self.escrow_token,
830 &self.token_program,
831 seed,
832 &self.mint.key(),
833 name,
834 bump,
835 amount,
836 )
837 }
838}