diff --git a/packages/evm/test/budgets/SimpleBudget.t.sol b/packages/evm/test/budgets/SimpleBudget.t.sol index a3df20e8..f829e1d8 100644 --- a/packages/evm/test/budgets/SimpleBudget.t.sol +++ b/packages/evm/test/budgets/SimpleBudget.t.sol @@ -199,11 +199,59 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { simpleBudget.allocate(data); } + function testAllocate_ERC20InvalidAllocation() public { + uint256 amount = 100 ether; + + // Approve SimpleBudget to spend tokens + mockERC20.approve(address(simpleBudget), amount); + + // Transfer 100 tokens to the budget + bytes memory data = _makeFungibleTransfer(ABudget.AssetType.ERC20, address(mockERC20), address(this), amount); + + // Set up the mock to manipulate the balance after transfer + vm.mockCall( + address(mockERC20), + abi.encodeWithSelector(mockERC20.balanceOf.selector, address(simpleBudget)), + abi.encode(amount - 1) // Return a balance that's 1 less than expected + ); + + // Expect revert due to InvalidAllocation + vm.expectRevert(abi.encodeWithSelector(ABudget.InvalidAllocation.selector, address(mockERC20), amount)); + simpleBudget.allocate(data); + + vm.clearMockedCalls(); + } + + function testAllocate_ERC1155InvalidAllocation() public { + uint256 tokenId = 42; + uint256 initialAmount = 100; + + // Approve SimpleBudget to spend tokens + mockERC1155.setApprovalForAll(address(simpleBudget), true); + + // Prepare allocation data + bytes memory allocateData = + _makeERC1155Transfer(address(mockERC1155), address(this), tokenId, initialAmount, ""); + + // Set up the mock to manipulate the balance after transfer + vm.mockCall( + address(mockERC1155), + abi.encodeWithSelector(mockERC1155.balanceOf.selector, address(simpleBudget), tokenId), + abi.encode(initialAmount - 1) // Return a balance that's 1 less than expected + ); + + // Expect revert due to InvalidAllocation + vm.expectRevert(abi.encodeWithSelector(ABudget.InvalidAllocation.selector, address(mockERC1155), initialAmount)); + simpleBudget.allocate(allocateData); + + vm.clearMockedCalls(); + } + /////////////////////////// - // SimpleBudget.reclaim // + // SimpleBudget.clawback // /////////////////////////// - function testReclaim() public { + function testClawback() public { // Approve the budget to transfer tokens mockERC20.approve(address(simpleBudget), 100 ether); @@ -220,7 +268,7 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { assertEq(simpleBudget.available(address(mockERC20)), 1 ether); } - function testReclaim_NativeBalance() public { + function testClawback_NativeBalance() public { // Allocate 100 ETH to the budget bytes memory data = _makeFungibleTransfer(ABudget.AssetType.ETH, address(0), address(this), 100 ether); simpleBudget.allocate{value: 100 ether}(data); @@ -234,7 +282,7 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { assertEq(simpleBudget.available(address(0)), 1 ether); } - function testReclaim_ERC1155() public { + function testClawback_ERC1155() public { // Approve the budget to transfer tokens mockERC1155.setApprovalForAll(address(simpleBudget), true); @@ -265,7 +313,7 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { assertEq(simpleBudget.available(address(mockERC1155), 42), 1); } - function testReclaim_ZeroAmount() public { + function testClawback_ZeroAmount() public { // Approve the budget to transfer tokens mockERC20.approve(address(simpleBudget), 100 ether); @@ -282,7 +330,7 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { assertEq(simpleBudget.available(address(mockERC20)), 0 ether); } - function testReclaim_ZeroAddress() public { + function testClawback_ZeroAddress() public { // Approve the budget to transfer tokens mockERC20.approve(address(simpleBudget), 100 ether); @@ -302,7 +350,7 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { assertEq(simpleBudget.available(address(mockERC20)), 100 ether); } - function testReclaim_InsufficientFunds() public { + function testClawback_InsufficientFunds() public { // Approve the budget to transfer tokens mockERC20.approve(address(simpleBudget), 100 ether); @@ -321,7 +369,7 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { simpleBudget.clawback(data); } - function testReclaim_ImproperData() public { + function testClawback_ImproperData() public { bytes memory data; // Approve the budget to transfer tokens @@ -338,7 +386,7 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { simpleBudget.clawback(data); } - function testReclaim_NotOwner() public { + function testClawback_NotOwner() public { // Approve the budget to transfer tokens mockERC20.approve(address(simpleBudget), 100 ether); @@ -354,6 +402,37 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { simpleBudget.clawback(data); } + function testClawback_InsufficientFundsERC1155() public { + // Approve the budget to transfer tokens + mockERC1155.setApprovalForAll(address(simpleBudget), true); + + // Allocate 100 of token ID 42 to the budget + bytes memory data = abi.encode( + ABudget.Transfer({ + assetType: ABudget.AssetType.ERC1155, + asset: address(mockERC1155), + target: address(this), + data: abi.encode(ABudget.ERC1155Payload({tokenId: 42, amount: 100, data: ""})) + }) + ); + simpleBudget.allocate(data); + assertEq(simpleBudget.available(address(mockERC1155), 42), 100); + + // Attempt to clawback more than available + bytes memory clawbackData = abi.encode( + ABudget.Transfer({ + assetType: ABudget.AssetType.ERC1155, + asset: address(mockERC1155), + target: address(this), + data: abi.encode(ABudget.ERC1155Payload({tokenId: 42, amount: 101, data: ""})) + }) + ); + + // Expect the InsufficientFunds revert + vm.expectRevert(abi.encodeWithSelector(ABudget.InsufficientFunds.selector, address(mockERC1155), 100, 101)); + simpleBudget.clawback(clawbackData); + } + /////////////////////////// // SimpleBudget.disburse // /////////////////////////// @@ -486,6 +565,23 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { simpleBudget.disburse(data); } + function testDisburse_InsufficientFundsERC1155() public { + // Approve the budget to transfer tokens + mockERC1155.setApprovalForAll(address(simpleBudget), true); + + // Allocate 100 tokens to the budget + bytes memory data = _makeERC1155Transfer(address(mockERC1155), address(this), 42, 100, bytes("")); + simpleBudget.allocate(data); + assertEq(simpleBudget.total(address(mockERC1155), 42), 100); + + // Disburse 101 tokens from the budget to the recipient + data = _makeERC1155Transfer(address(mockERC1155), address(1), 42, 101, bytes("")); + vm.expectRevert( + abi.encodeWithSelector(ABudget.InsufficientFunds.selector, address(mockERC1155), uint256(100), uint256(101)) + ); + simpleBudget.disburse(data); + } + function testDisburse_ImproperData() public { bytes memory data; @@ -568,6 +664,37 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { simpleBudget.disburseBatch(requests); } + function testDisburse_ERC1155_ToZeroAddress() public { + address token = address(mockERC1155); + uint256 tokenId = 42; + uint256 amount = 10; + + // Transfer tokens to the SimpleBudget contract + mockERC1155.safeTransferFrom(address(this), address(simpleBudget), tokenId, amount, ""); + + // Verify the transfer + assertEq(mockERC1155.balanceOf(address(simpleBudget), tokenId), amount); + + // Disburse the tokens to the zero address + bytes memory disburseData = abi.encode( + ABudget.Transfer({ + assetType: ABudget.AssetType.ERC1155, + asset: token, + target: address(0), + data: abi.encode(ABudget.ERC1155Payload({tokenId: tokenId, amount: amount, data: ""})) + }) + ); + + // Expect the disbursement to fail + vm.expectRevert( + abi.encodeWithSelector(ABudget.TransferFailed.selector, address(mockERC1155), address(0), amount) + ); + simpleBudget.disburse(disburseData); + + // Ensure the budget still has 10 tokens + assertEq(mockERC1155.balanceOf(address(simpleBudget), tokenId), amount); + } + //////////////////////// // SimpleBudget.total // //////////////////////// @@ -845,6 +972,34 @@ contract SimpleBudgetTest is Test, IERC1155Receiver { assertEq(simpleBudget.available(address(0)), 1 ether); } + function testOnERC1155Received() public view { + // Call onERC1155Received with dummy values + bytes4 result = simpleBudget.onERC1155Received( + address(0xc0ffee), // operator + address(0xdeadbeef), // from + 1, // id + 1, // amount + "" // data + ); + + // Check if it returns the correct selector + assertEq(result, IERC1155Receiver.onERC1155Received.selector, "Should return correct selector"); + } + + function testOnERC1155BatchReceived() public view { + // Call onERC1155BatchReceived with dummy values + bytes4 result = simpleBudget.onERC1155BatchReceived( + address(0xc0ffee), // operator + address(0xdeadbeef), // from + new uint256[](1), // ids + new uint256[](1), // amounts + "" // data + ); + + // Check if it returns the correct selector + assertEq(result, IERC1155Receiver.onERC1155BatchReceived.selector, "Should return correct selector"); + } + /////////////////////////// // Test Helper Functions // ///////////////////////////