add love contract
9bf25a7 parent: f37bb94 added
script/Love.s.sol +18 -0 | new file mode 100644 | ||
| @@ -0,0 +1,18 @@ | ||
| 1 | +// SPDX-License-Identifier: MIT | |
| 2 | +pragma solidity ^0.8.30; | |
| 3 | + | |
| 4 | +import {Love} from "../src/Love.sol"; | |
| 5 | +import {Script, console} from "forge-std/Script.sol"; | |
| 6 | + | |
| 7 | +contract LoveScript is Script { | |
| 8 | + Love public love; | |
| 9 | + | |
| 10 | + function run() public { | |
| 11 | + vm.startBroadcast(); | |
| 12 | + | |
| 13 | + love = new Love(); | |
| 14 | + console.log("Love deployed at", address(love)); | |
| 15 | + | |
| 16 | + vm.stopBroadcast(); | |
| 17 | + } | |
| 18 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | +// SPDX-License-Identifier: MIT | ||
| 2 | +pragma solidity ^0.8.30; | ||
| 3 | + | ||
| 4 | +import {Love} from "../src/Love.sol"; | ||
| 5 | +import {Script, console} from "forge-std/Script.sol"; | ||
| 6 | + | ||
| 7 | +contract LoveScript is Script { | ||
| 8 | + Love public love; | ||
| 9 | + | ||
| 10 | + function run() public { | ||
| 11 | + vm.startBroadcast(); | ||
| 12 | + | ||
| 13 | + love = new Love(); | ||
| 14 | + console.log("Love deployed at", address(love)); | ||
| 15 | + | ||
| 16 | + vm.stopBroadcast(); | ||
| 17 | + } | ||
| 18 | +} | ||
added
src/Love.sol +25 -0 | new file mode 100644 | ||
| @@ -0,0 +1,25 @@ | ||
| 1 | +// SPDX-License-Identifier: MIT | |
| 2 | +pragma solidity ^0.8.30; | |
| 3 | + | |
| 4 | +/// @title Love | |
| 5 | +/// @notice A minimal on-chain counter of love sent between addresses. | |
| 6 | +contract Love { | |
| 7 | + mapping(address sender => mapping(address recipient => uint256 amount)) public sent; | |
| 8 | + mapping(address recipient => uint256 amount) public received; | |
| 9 | + | |
| 10 | + event LoveSent(address indexed from, address indexed to, uint256 amount); | |
| 11 | + | |
| 12 | + error SelfLove(); | |
| 13 | + error ZeroAmount(); | |
| 14 | + | |
| 15 | + /// @notice Send `amount` units of love to `to`. | |
| 16 | + function send(address to, uint256 amount) external { | |
| 17 | + if (to == msg.sender) revert SelfLove(); | |
| 18 | + if (amount == 0) revert ZeroAmount(); | |
| 19 | + | |
| 20 | + sent[msg.sender][to] += amount; | |
| 21 | + received[to] += amount; | |
| 22 | + | |
| 23 | + emit LoveSent(msg.sender, to, amount); | |
| 24 | + } | |
| 25 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | +// SPDX-License-Identifier: MIT | ||
| 2 | +pragma solidity ^0.8.30; | ||
| 3 | + | ||
| 4 | +/// @title Love | ||
| 5 | +/// @notice A minimal on-chain counter of love sent between addresses. | ||
| 6 | +contract Love { | ||
| 7 | + mapping(address sender => mapping(address recipient => uint256 amount)) public sent; | ||
| 8 | + mapping(address recipient => uint256 amount) public received; | ||
| 9 | + | ||
| 10 | + event LoveSent(address indexed from, address indexed to, uint256 amount); | ||
| 11 | + | ||
| 12 | + error SelfLove(); | ||
| 13 | + error ZeroAmount(); | ||
| 14 | + | ||
| 15 | + /// @notice Send `amount` units of love to `to`. | ||
| 16 | + function send(address to, uint256 amount) external { | ||
| 17 | + if (to == msg.sender) revert SelfLove(); | ||
| 18 | + if (amount == 0) revert ZeroAmount(); | ||
| 19 | + | ||
| 20 | + sent[msg.sender][to] += amount; | ||
| 21 | + received[to] += amount; | ||
| 22 | + | ||
| 23 | + emit LoveSent(msg.sender, to, amount); | ||
| 24 | + } | ||
| 25 | +} | ||
added
test/Love.t.sol +67 -0 | new file mode 100644 | ||
| @@ -0,0 +1,67 @@ | ||
| 1 | +// SPDX-License-Identifier: MIT | |
| 2 | +pragma solidity ^0.8.30; | |
| 3 | + | |
| 4 | +import {Love} from "../src/Love.sol"; | |
| 5 | +import {Test} from "forge-std/Test.sol"; | |
| 6 | + | |
| 7 | +contract LoveTest is Test { | |
| 8 | + Love public love; | |
| 9 | + | |
| 10 | + address alice = makeAddr("alice"); | |
| 11 | + address bob = makeAddr("bob"); | |
| 12 | + | |
| 13 | + event LoveSent(address indexed from, address indexed to, uint256 amount); | |
| 14 | + | |
| 15 | + function setUp() public { | |
| 16 | + love = new Love(); | |
| 17 | + } | |
| 18 | + | |
| 19 | + function test_Send() public { | |
| 20 | + vm.prank(alice); | |
| 21 | + love.send(bob, 1); | |
| 22 | + | |
| 23 | + assertEq(love.sent(alice, bob), 1); | |
| 24 | + assertEq(love.received(bob), 1); | |
| 25 | + } | |
| 26 | + | |
| 27 | + function test_SendAccumulates() public { | |
| 28 | + vm.startPrank(alice); | |
| 29 | + love.send(bob, 2); | |
| 30 | + love.send(bob, 3); | |
| 31 | + vm.stopPrank(); | |
| 32 | + | |
| 33 | + assertEq(love.sent(alice, bob), 5); | |
| 34 | + assertEq(love.received(bob), 5); | |
| 35 | + } | |
| 36 | + | |
| 37 | + function test_SendEmitsEvent() public { | |
| 38 | + vm.expectEmit(true, true, false, true); | |
| 39 | + emit LoveSent(alice, bob, 7); | |
| 40 | + | |
| 41 | + vm.prank(alice); | |
| 42 | + love.send(bob, 7); | |
| 43 | + } | |
| 44 | + | |
| 45 | + function test_RevertWhen_SendingToSelf() public { | |
| 46 | + vm.prank(alice); | |
| 47 | + vm.expectRevert(Love.SelfLove.selector); | |
| 48 | + love.send(alice, 1); | |
| 49 | + } | |
| 50 | + | |
| 51 | + function test_RevertWhen_AmountIsZero() public { | |
| 52 | + vm.prank(alice); | |
| 53 | + vm.expectRevert(Love.ZeroAmount.selector); | |
| 54 | + love.send(bob, 0); | |
| 55 | + } | |
| 56 | + | |
| 57 | + function testFuzz_Send(address from, address to, uint256 amount) public { | |
| 58 | + vm.assume(from != to); | |
| 59 | + amount = bound(amount, 1, type(uint256).max); | |
| 60 | + | |
| 61 | + vm.prank(from); | |
| 62 | + love.send(to, amount); | |
| 63 | + | |
| 64 | + assertEq(love.sent(from, to), amount); | |
| 65 | + assertEq(love.received(to), amount); | |
| 66 | + } | |
| 67 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | +// SPDX-License-Identifier: MIT | ||
| 2 | +pragma solidity ^0.8.30; | ||
| 3 | + | ||
| 4 | +import {Love} from "../src/Love.sol"; | ||
| 5 | +import {Test} from "forge-std/Test.sol"; | ||
| 6 | + | ||
| 7 | +contract LoveTest is Test { | ||
| 8 | + Love public love; | ||
| 9 | + | ||
| 10 | + address alice = makeAddr("alice"); | ||
| 11 | + address bob = makeAddr("bob"); | ||
| 12 | + | ||
| 13 | + event LoveSent(address indexed from, address indexed to, uint256 amount); | ||
| 14 | + | ||
| 15 | + function setUp() public { | ||
| 16 | + love = new Love(); | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + function test_Send() public { | ||
| 20 | + vm.prank(alice); | ||
| 21 | + love.send(bob, 1); | ||
| 22 | + | ||
| 23 | + assertEq(love.sent(alice, bob), 1); | ||
| 24 | + assertEq(love.received(bob), 1); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + function test_SendAccumulates() public { | ||
| 28 | + vm.startPrank(alice); | ||
| 29 | + love.send(bob, 2); | ||
| 30 | + love.send(bob, 3); | ||
| 31 | + vm.stopPrank(); | ||
| 32 | + | ||
| 33 | + assertEq(love.sent(alice, bob), 5); | ||
| 34 | + assertEq(love.received(bob), 5); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + function test_SendEmitsEvent() public { | ||
| 38 | + vm.expectEmit(true, true, false, true); | ||
| 39 | + emit LoveSent(alice, bob, 7); | ||
| 40 | + | ||
| 41 | + vm.prank(alice); | ||
| 42 | + love.send(bob, 7); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + function test_RevertWhen_SendingToSelf() public { | ||
| 46 | + vm.prank(alice); | ||
| 47 | + vm.expectRevert(Love.SelfLove.selector); | ||
| 48 | + love.send(alice, 1); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + function test_RevertWhen_AmountIsZero() public { | ||
| 52 | + vm.prank(alice); | ||
| 53 | + vm.expectRevert(Love.ZeroAmount.selector); | ||
| 54 | + love.send(bob, 0); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + function testFuzz_Send(address from, address to, uint256 amount) public { | ||
| 58 | + vm.assume(from != to); | ||
| 59 | + amount = bound(amount, 1, type(uint256).max); | ||
| 60 | + | ||
| 61 | + vm.prank(from); | ||
| 62 | + love.send(to, amount); | ||
| 63 | + | ||
| 64 | + assertEq(love.sent(from, to), amount); | ||
| 65 | + assertEq(love.received(to), amount); | ||
| 66 | + } | ||
| 67 | +} | ||