@@ -1532,3 +1532,277 @@ fn test_partial_withdrawal_does_not_complete() {
15321532 assert ! ( s. is_active) ;
15331533 assert ! ( !client. is_stream_completed( & id) ) ;
15341534}
1535+
1536+ #[ test]
1537+ fn test_withdraw_on_paused_then_resume ( ) {
1538+ let env = Env :: default ( ) ;
1539+ env. mock_all_auths ( ) ;
1540+ let ( token, _) = create_token ( & env) ;
1541+ let sender = Address :: generate ( & env) ;
1542+ let recipient = Address :: generate ( & env) ;
1543+ mint ( & env, & token, & sender, 10_000 ) ;
1544+
1545+ let client = create_contract ( & env) ;
1546+ let id = client. create_stream ( & sender, & recipient, & token, & 10_000 , & 100 ) ;
1547+
1548+ env. ledger ( ) . with_mut ( |l| l. timestamp += 50 ) ;
1549+ client. pause_stream ( & sender, & id) ;
1550+
1551+ env. ledger ( ) . with_mut ( |l| l. timestamp += 50 ) ;
1552+ client. resume_stream ( & sender, & id) ;
1553+
1554+ env. ledger ( ) . with_mut ( |l| l. timestamp += 50 ) ;
1555+ let claimable = client. get_claimable_amount ( & id) ;
1556+
1557+ assert ! ( claimable. is_some( ) && claimable. unwrap( ) > 0 ) ;
1558+ }
1559+
1560+ #[ test]
1561+ fn test_multiple_pause_resume_preserves_state ( ) {
1562+ let env = Env :: default ( ) ;
1563+ env. mock_all_auths ( ) ;
1564+ let ( token, _) = create_token ( & env) ;
1565+ let sender = Address :: generate ( & env) ;
1566+ let recipient = Address :: generate ( & env) ;
1567+ mint ( & env, & token, & sender, 10_000 ) ;
1568+
1569+ let client = create_contract ( & env) ;
1570+ let id = client. create_stream ( & sender, & recipient, & token, & 10_000 , & 50 ) ;
1571+
1572+ for _ in 0 ..3 {
1573+ env. ledger ( ) . with_mut ( |l| l. timestamp += 100 ) ;
1574+ client. pause_stream ( & sender, & id) ;
1575+ env. ledger ( ) . with_mut ( |l| l. timestamp += 50 ) ;
1576+ client. resume_stream ( & sender, & id) ;
1577+ }
1578+
1579+ let stream = client. get_stream ( & id) . unwrap ( ) ;
1580+ assert ! ( stream. is_active) ;
1581+ assert ! ( !stream. paused) ;
1582+ }
1583+
1584+ #[ test]
1585+ fn test_cancel_while_paused_keeps_inactive ( ) {
1586+ let env = Env :: default ( ) ;
1587+ env. mock_all_auths ( ) ;
1588+ let ( token, _) = create_token ( & env) ;
1589+ let sender = Address :: generate ( & env) ;
1590+ let recipient = Address :: generate ( & env) ;
1591+ mint ( & env, & token, & sender, 1_000 ) ;
1592+
1593+ let client = create_contract ( & env) ;
1594+ let id = client. create_stream ( & sender, & recipient, & token, & 1_000 , & 100 ) ;
1595+
1596+ env. ledger ( ) . with_mut ( |l| l. timestamp += 300 ) ;
1597+ client. pause_stream ( & sender, & id) ;
1598+
1599+ env. ledger ( ) . with_mut ( |l| l. timestamp += 200 ) ;
1600+ client. cancel_stream ( & sender, & id) ;
1601+
1602+ let stream = client. get_stream ( & id) . unwrap ( ) ;
1603+ assert ! ( !stream. is_active) ;
1604+ assert_eq ! ( stream. status, StreamStatus :: Cancelled ) ;
1605+ }
1606+
1607+ #[ test]
1608+ fn test_top_up_while_paused_increases_deposited ( ) {
1609+ let env = Env :: default ( ) ;
1610+ env. mock_all_auths ( ) ;
1611+ let ( token, _) = create_token ( & env) ;
1612+ let sender = Address :: generate ( & env) ;
1613+ let recipient = Address :: generate ( & env) ;
1614+ mint ( & env, & token, & sender, 2_000 ) ;
1615+
1616+ let client = create_contract ( & env) ;
1617+ let id = client. create_stream ( & sender, & recipient, & token, & 1_000 , & 100 ) ;
1618+
1619+ env. ledger ( ) . with_mut ( |l| l. timestamp += 500 ) ;
1620+ client. pause_stream ( & sender, & id) ;
1621+
1622+ let old_deposited = client. get_stream ( & id) . unwrap ( ) . deposited_amount ;
1623+ client. top_up_stream ( & sender, & id, & 1_000 ) ;
1624+ let new_deposited = client. get_stream ( & id) . unwrap ( ) . deposited_amount ;
1625+
1626+ assert ! ( new_deposited > old_deposited) ;
1627+ }
1628+
1629+ #[ test]
1630+ fn test_withdraw_after_long_stream_runtime_is_bounded ( ) {
1631+ let env = Env :: default ( ) ;
1632+ env. mock_all_auths ( ) ;
1633+ let ( token, _) = create_token ( & env) ;
1634+ let sender = Address :: generate ( & env) ;
1635+ let recipient = Address :: generate ( & env) ;
1636+ mint ( & env, & token, & sender, 5_000 ) ;
1637+
1638+ let client = create_contract ( & env) ;
1639+ let id = client. create_stream ( & sender, & recipient, & token, & 5_000 , & 10 ) ;
1640+
1641+ env. ledger ( ) . with_mut ( |l| l. timestamp += 10_000 ) ;
1642+ let withdrawn = client. withdraw ( & recipient, & id) ;
1643+
1644+ assert ! ( withdrawn <= 5_000 ) ;
1645+ }
1646+
1647+ // ─── Property-Based Fuzz Tests ────────────────────────────────────────────────
1648+
1649+ #[ test]
1650+ fn test_fuzz_withdrawn_never_exceeds_deposited ( ) {
1651+ let env = Env :: default ( ) ;
1652+ env. mock_all_auths ( ) ;
1653+ let ( token, _) = create_token ( & env) ;
1654+
1655+ let mut seed = 1u64 ;
1656+ for iteration in 0 ..50 {
1657+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
1658+ let amount = 1 + ( ( seed / 2 ) % 100_000 ) as i128 ;
1659+
1660+ let sender = Address :: generate ( & env) ;
1661+ let recipient = Address :: generate ( & env) ;
1662+ mint ( & env, & token, & sender, amount) ;
1663+
1664+ let client = create_contract ( & env) ;
1665+ let id = client. create_stream ( & sender, & recipient, & token, & amount, & 100 ) ;
1666+
1667+ env. ledger ( ) . with_mut ( |l| l. timestamp += 1000 ) ;
1668+ let withdrawn = client. withdraw ( & recipient, & id) ;
1669+
1670+ let stream = client. get_stream ( & id) . unwrap ( ) ;
1671+ assert ! (
1672+ stream. withdrawn_amount <= stream. deposited_amount,
1673+ "Iteration {}: withdrawn {} > deposited {}" ,
1674+ iteration,
1675+ stream. withdrawn_amount,
1676+ stream. deposited_amount
1677+ ) ;
1678+ assert ! ( withdrawn <= amount) ;
1679+ }
1680+ }
1681+
1682+ #[ test]
1683+ fn test_fuzz_claimable_never_exceeds_remaining ( ) {
1684+ let env = Env :: default ( ) ;
1685+ env. mock_all_auths ( ) ;
1686+ let ( token, _) = create_token ( & env) ;
1687+
1688+ let mut seed = 2u64 ;
1689+ for iteration in 0 ..50 {
1690+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
1691+ let amount = 1 + ( ( seed / 2 ) % 100_000 ) as i128 ;
1692+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
1693+ let duration = 1 + ( seed % 10_000 ) as u64 ;
1694+
1695+ let sender = Address :: generate ( & env) ;
1696+ let recipient = Address :: generate ( & env) ;
1697+ mint ( & env, & token, & sender, amount) ;
1698+
1699+ let client = create_contract ( & env) ;
1700+ let id = client. create_stream ( & sender, & recipient, & token, & amount, & duration) ;
1701+
1702+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
1703+ let elapsed = seed % duration;
1704+ env. ledger ( ) . with_mut ( |l| l. timestamp += elapsed) ;
1705+
1706+ let claimable = client. get_claimable_amount ( & id) . unwrap_or ( 0 ) ;
1707+ let stream = client. get_stream ( & id) . unwrap ( ) ;
1708+ let remaining = stream. deposited_amount - stream. withdrawn_amount ;
1709+
1710+ assert ! (
1711+ claimable <= remaining,
1712+ "Iteration {}: claimable {} > remaining {}" ,
1713+ iteration,
1714+ claimable,
1715+ remaining
1716+ ) ;
1717+ }
1718+ }
1719+
1720+ #[ test]
1721+ fn test_fuzz_cancel_early_refunds ( ) {
1722+ let env = Env :: default ( ) ;
1723+ env. mock_all_auths ( ) ;
1724+ let ( token, _) = create_token ( & env) ;
1725+
1726+ let mut seed = 3u64 ;
1727+ for iteration in 0 ..50 {
1728+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
1729+ let amount = 10_000 + ( ( seed / 2 ) % 100_000 ) as i128 ;
1730+
1731+ let sender = Address :: generate ( & env) ;
1732+ let recipient = Address :: generate ( & env) ;
1733+ mint ( & env, & token, & sender, amount) ;
1734+
1735+ let client = create_contract ( & env) ;
1736+ let id = client. create_stream ( & sender, & recipient, & token, & amount, & 10 ) ;
1737+
1738+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
1739+ let partial_time = 1 + ( seed % 100 ) as u64 ;
1740+ env. ledger ( ) . with_mut ( |l| l. timestamp += partial_time) ;
1741+
1742+ client. cancel_stream ( & sender, & id) ;
1743+ let stream = client. get_stream ( & id) . unwrap ( ) ;
1744+ assert ! ( !stream. is_active, "Iteration {}: stream should be inactive after cancel" , iteration) ;
1745+ }
1746+ }
1747+
1748+ #[ test]
1749+ fn test_fuzz_pause_resume_maintains_active_state ( ) {
1750+ let env = Env :: default ( ) ;
1751+ env. mock_all_auths ( ) ;
1752+ let ( token, _) = create_token ( & env) ;
1753+
1754+ let mut seed = 4u64 ;
1755+ for iteration in 0 ..25 {
1756+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
1757+ let amount = 100_000 + ( ( seed / 2 ) % 100_000 ) as i128 ;
1758+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
1759+ let rate = 10 + ( seed % 100 ) as u64 ;
1760+
1761+ let sender = Address :: generate ( & env) ;
1762+ let recipient = Address :: generate ( & env) ;
1763+ mint ( & env, & token, & sender, amount) ;
1764+
1765+ let client = create_contract ( & env) ;
1766+ let id = client. create_stream ( & sender, & recipient, & token, & amount, & rate) ;
1767+
1768+ for i in 0 ..3 {
1769+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
1770+ let sleep_time = 10 + ( seed % 50 ) as u64 ;
1771+ env. ledger ( ) . with_mut ( |l| l. timestamp += sleep_time) ;
1772+
1773+ let stream = client. get_stream ( & id) . unwrap ( ) ;
1774+ if i % 2 == 0 {
1775+ client. pause_stream ( & sender, & id) ;
1776+ } else if stream. paused {
1777+ client. resume_stream ( & sender, & id) ;
1778+ }
1779+ }
1780+
1781+ let stream = client. get_stream ( & id) . unwrap ( ) ;
1782+ assert ! ( stream. is_active, "Iteration {}: stream should remain active" , iteration) ;
1783+ }
1784+ }
1785+
1786+ #[ test]
1787+ fn test_fuzz_large_amount_no_overflow ( ) {
1788+ let env = Env :: default ( ) ;
1789+ env. mock_all_auths ( ) ;
1790+ let ( token, _) = create_token ( & env) ;
1791+
1792+ let large_amounts = [ 1_000_000_000_000i128 , 10_000_000_000_000i128 , 100_000_000_000_000i128 ] ;
1793+
1794+ for amount in large_amounts. iter ( ) {
1795+ let sender = Address :: generate ( & env) ;
1796+ let recipient = Address :: generate ( & env) ;
1797+ mint ( & env, & token, & sender, * amount) ;
1798+
1799+ let client = create_contract ( & env) ;
1800+ let id = client. create_stream ( & sender, & recipient, & token, amount, & 100 ) ;
1801+
1802+ env. ledger ( ) . with_mut ( |l| l. timestamp += 1_000 ) ;
1803+
1804+ let claimable = client. get_claimable_amount ( & id) . unwrap_or ( 0 ) ;
1805+ assert ! ( claimable > 0 ) ;
1806+ assert ! ( claimable <= * amount) ;
1807+ }
1808+ }
0 commit comments