@@ -16,7 +16,7 @@ abstract contract BudgetTest is FirmTest {
1616 SafeStub safe;
1717 RolesStub roles;
1818 Budget budget;
19- address token;
19+ address token; // set in deriving contracts
2020
2121 address SPENDER = account ("spender " );
2222 address RECEIVER = account ("receiver " );
@@ -25,7 +25,7 @@ abstract contract BudgetTest is FirmTest {
2525 function setUp () public virtual {
2626 safe = new SafeStub ();
2727 roles = new RolesStub ();
28- budget = Budget (createProxy (new Budget (), abi.encodeCall (Budget.initialize, (safe, roles, address ( 0 ) ))));
28+ budget = Budget (createProxy (new Budget (), abi.encodeCall (Budget.initialize, (safe, roles, token ))));
2929 }
3030
3131 function testInitialState () public {
@@ -35,7 +35,7 @@ abstract contract BudgetTest is FirmTest {
3535
3636 function testCannotReinit () public {
3737 vm.expectRevert (abi.encodeWithSelector (SafeAware.AlreadyInitialized.selector ));
38- budget.initialize (safe, roles, address ( 0 ) );
38+ budget.initialize (safe, roles, token );
3939 }
4040
4141 function testCreateAllowance () public returns (uint256 allowanceId ) {
@@ -81,16 +81,59 @@ abstract contract BudgetTest is FirmTest {
8181 assertEq (spender, RECEIVER);
8282 }
8383
84+ function testCantUpdateSpenderToZeroAddress () public {
85+ uint256 allowanceId = testCreateAllowance ();
86+
87+ vm.startPrank (address (safe));
88+ vm.expectRevert (abi.encodeWithSelector (Budget.BadInput.selector ));
89+ budget.setAllowanceSpender (allowanceId, address (0 ));
90+ }
91+
92+ function testCantSetAllowanceAmountToZeroIfTopLevel () public {
93+ uint256 allowanceId = testCreateAllowance ();
94+
95+ vm.prank (address (safe));
96+ vm.expectRevert (abi.encodeWithSelector (Budget.InheritedAmountNotAllowed.selector ));
97+ budget.setAllowanceAmount (allowanceId, 0 );
98+ }
99+
100+ function testCantSetAllowanceAmountToZeroIfNotInherited () public {
101+ uint256 allowanceId = testCreateAllowance ();
102+ vm.prank (address (SPENDER));
103+ uint256 childAllowanceId = budget.createAllowance (
104+ allowanceId, SPENDER, token, 10 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
105+ );
106+ vm.prank (address (SPENDER));
107+ vm.expectRevert (abi.encodeWithSelector (Budget.InheritedAmountNotAllowed.selector ));
108+ budget.setAllowanceAmount (childAllowanceId, 0 );
109+ }
110+
84111 function testNotOwnerCannotCreateTopLevelAllowance () public {
85112 vm.expectRevert (abi.encodeWithSelector (Budget.UnauthorizedNotAllowanceAdmin.selector , 0 ));
86113 createDailyAllowance (SPENDER, 0 );
87114 }
88115
89- function testInvalidTimeshiftsRevert () public {
116+ function testCantCreateAllowanceWithZeroToken () public {
117+ vm.prank (address (safe));
118+ vm.expectRevert (abi.encodeWithSelector (Budget.BadInput.selector ));
119+ budget.createAllowance (
120+ NO_PARENT_ID, SPENDER, address (0 ), 10 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
121+ );
122+ }
123+
124+ function testCantCreateAllowanceWithZeroSpender () public {
125+ vm.prank (address (safe));
126+ vm.expectRevert (abi.encodeWithSelector (Budget.BadInput.selector ));
127+ budget.createAllowance (
128+ NO_PARENT_ID, address (0 ), token, 10 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
129+ );
130+ }
131+
132+ function testCantCreateAllowanceWithInvalidTimeshift () public {
90133 vm.prank (address (safe));
91134 vm.expectRevert (abi.encodeWithSelector (TimeShiftLib.InvalidTimeShift.selector ));
92135 budget.createAllowance (
93- NO_PARENT_ID, SPENDER, address ( 0 ) , 10 , TimeShift (TimeShiftLib.TimeUnit.Inherit, 0 ).encode (), ""
136+ NO_PARENT_ID, SPENDER, token , 10 , TimeShift (TimeShiftLib.TimeUnit.Inherit, 0 ).encode (), ""
94137 );
95138 }
96139
@@ -108,7 +151,7 @@ abstract contract BudgetTest is FirmTest {
108151 vm.prank (address (safe));
109152 vm.expectRevert (abi.encodeWithSelector (RolesAuth.UnexistentRole.selector , badRoleId));
110153 budget.createAllowance (
111- NO_PARENT_ID, roleFlag (badRoleId), address ( 0 ) , 10 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
154+ NO_PARENT_ID, roleFlag (badRoleId), token , 10 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
112155 );
113156 }
114157
@@ -187,11 +230,11 @@ abstract contract BudgetTest is FirmTest {
187230
188231 vm.prank (address (safe));
189232 topLevelAllowance = budget.createAllowance (
190- NO_PARENT_ID, SPENDER, address ( 0 ) , 10 , TimeShift (TimeShiftLib.TimeUnit.Monthly, 0 ).encode (), ""
233+ NO_PARENT_ID, SPENDER, token , 10 , TimeShift (TimeShiftLib.TimeUnit.Monthly, 0 ).encode (), ""
191234 );
192235 vm.prank (SPENDER);
193236 subAllowance = budget.createAllowance (
194- topLevelAllowance, SOMEONE_ELSE, address ( 0 ) , 5 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
237+ topLevelAllowance, SOMEONE_ELSE, token , 5 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
195238 );
196239
197240 assertExecutePayment (SOMEONE_ELSE, subAllowance, RECEIVER, 5 , initialTime + 1 days);
@@ -233,11 +276,11 @@ abstract contract BudgetTest is FirmTest {
233276
234277 vm.prank (address (safe));
235278 uint256 topLevelAllowance = budget.createAllowance (
236- NO_PARENT_ID, SPENDER, address ( 0 ) , 10 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
279+ NO_PARENT_ID, SPENDER, token , 10 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
237280 );
238281 vm.prank (SPENDER);
239282 uint256 subAllowance = budget.createAllowance (
240- topLevelAllowance, SOMEONE_ELSE, address ( 0 ) , 5 , TimeShift (TimeShiftLib.TimeUnit.Inherit, 0 ).encode (), ""
283+ topLevelAllowance, SOMEONE_ELSE, token , 5 , TimeShift (TimeShiftLib.TimeUnit.Inherit, 0 ).encode (), ""
241284 );
242285
243286 assertExecutePayment (SOMEONE_ELSE, subAllowance, RECEIVER, 5 , initialTime + 1 days);
@@ -249,17 +292,17 @@ abstract contract BudgetTest is FirmTest {
249292
250293 vm.prank (address (safe));
251294 uint256 allowance1 = budget.createAllowance (
252- NO_PARENT_ID, SPENDER, address ( 0 ) , 10 , TimeShift (TimeShiftLib.TimeUnit.Monthly, 0 ).encode (), ""
295+ NO_PARENT_ID, SPENDER, token , 10 , TimeShift (TimeShiftLib.TimeUnit.Monthly, 0 ).encode (), ""
253296 );
254297 vm.startPrank (SPENDER);
255298 uint256 allowance2 = budget.createAllowance (
256- allowance1, SPENDER, address ( 0 ) , 5 , TimeShift (TimeShiftLib.TimeUnit.Inherit, 0 ).encode (), ""
299+ allowance1, SPENDER, token , 5 , TimeShift (TimeShiftLib.TimeUnit.Inherit, 0 ).encode (), ""
257300 );
258301 uint256 allowance3 = budget.createAllowance (
259- allowance2, SPENDER, address ( 0 ) , 2 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
302+ allowance2, SPENDER, token , 2 , TimeShift (TimeShiftLib.TimeUnit.Daily, 0 ).encode (), ""
260303 );
261304 uint256 allowance4 = budget.createAllowance (
262- allowance3, SPENDER, address ( 0 ) , 1 , TimeShift (TimeShiftLib.TimeUnit.Inherit, 0 ).encode (), ""
305+ allowance3, SPENDER, token , 1 , TimeShift (TimeShiftLib.TimeUnit.Inherit, 0 ).encode (), ""
263306 );
264307 vm.stopPrank ();
265308
@@ -522,10 +565,13 @@ abstract contract BudgetTest is FirmTest {
522565 initialSpent = 0 ;
523566 }
524567
568+ uint256 balanceBefore = token == NATIVE_ASSET ? to.balance : ERC20Token (token_).balanceOf (to);
525569 vm.prank (actor);
526570 vm.expectEmit (true , true , true , true );
527571 emit PaymentExecuted (allowanceId, actor, token_, to, amount, expectedNextResetTime, "" );
528572 budget.executePayment (allowanceId, to, amount, "" );
573+ uint256 balanceAfter = token == NATIVE_ASSET ? to.balance : ERC20Token (token_).balanceOf (to);
574+ assertEq (balanceAfter - balanceBefore, amount);
529575
530576 (,, uint256 spent ,, uint40 nextResetTime ,,,) = budget.allowances (allowanceId);
531577
0 commit comments