diff --git a/.vscode/settings.json b/.vscode/settings.json index 04dfdf6..71afdba 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,4 +2,5 @@ "search.exclude": { "/lib/**": true, }, + "commentTranslate.source": "Copilot", } \ No newline at end of file diff --git a/script/HelperConfig.s.sol b/script/HelperConfig.s.sol index 53148cd..59615a8 100644 --- a/script/HelperConfig.s.sol +++ b/script/HelperConfig.s.sol @@ -3,7 +3,8 @@ pragma solidity ^0.8.18; import {Script} from "forge-std/Script.sol"; import {Raffle} from "../src/Raffle.sol"; -import {VRFCoordinatorV2_5Mock} from "chainlink-brownie-contracts/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2_5Mock.sol"; +import {VRFCoordinatorV2_5Mock} from + "chainlink-brownie-contracts/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2_5Mock.sol"; import {LinkToken} from "../test/mock/LinkToken.sol"; abstract contract Constants { @@ -12,7 +13,7 @@ abstract contract Constants { int256 public MOCK_WEI_PER_UINT_LINK = 4e18; } -contract HelperConfig is Script, Constants{ +contract HelperConfig is Script, Constants { struct NetworkConfig { uint256 entranceFee; uint256 interval; @@ -22,6 +23,7 @@ contract HelperConfig is Script, Constants{ bytes32 keyHash; address link; } + NetworkConfig public activeNetworkConfig; constructor() { @@ -33,16 +35,15 @@ contract HelperConfig is Script, Constants{ } function getSepoliaEthConfig() public pure returns (NetworkConfig memory) { - return - NetworkConfig({ - entranceFee: 0.01 ether, - interval: 30, - vrfCoordinator: 0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B, - keyHash: 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae, - subscriptionId: 0, // Update with subId; - callbackGasLimit: 500000, - link: 0x779877A7B0D9E8603169DdbD7836e478b4624789 - }); + return NetworkConfig({ + entranceFee: 0.01 ether, + interval: 30, + vrfCoordinator: 0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B, + keyHash: 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae, + subscriptionId: 0, // Update with subId; + callbackGasLimit: 500000, + link: 0x779877A7B0D9E8603169DdbD7836e478b4624789 + }); } function getOrCreateAnvilConfig() public returns (NetworkConfig memory) { @@ -50,29 +51,24 @@ contract HelperConfig is Script, Constants{ return activeNetworkConfig; } - vm.startBroadcast(); - VRFCoordinatorV2_5Mock coordinator = new VRFCoordinatorV2_5Mock( - MOCK_BASE_FEE, - MOCK_GAS_PRICE_LINK, - MOCK_WEI_PER_UINT_LINK - ); + VRFCoordinatorV2_5Mock coordinator = + new VRFCoordinatorV2_5Mock(MOCK_BASE_FEE, MOCK_GAS_PRICE_LINK, MOCK_WEI_PER_UINT_LINK); LinkToken link = new LinkToken(); vm.stopBroadcast(); - return - NetworkConfig({ - entranceFee: 0.01 ether, - interval: 30, - vrfCoordinator: address(coordinator), - keyHash: 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae, - subscriptionId: 0, // Update with subId; - callbackGasLimit: 500000, - link: address(link) - }); + return NetworkConfig({ + entranceFee: 0.01 ether, + interval: 30, + vrfCoordinator: address(coordinator), + keyHash: 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae, + subscriptionId: 0, // Update with subId; + callbackGasLimit: 500000, + link: address(link) + }); } - function getNetworkConfig() public view returns(NetworkConfig memory) { + function getNetworkConfig() public view returns (NetworkConfig memory) { return activeNetworkConfig; } } diff --git a/script/Interaction.s.sol b/script/Interaction.s.sol index 58ae49a..2edd881 100644 --- a/script/Interaction.s.sol +++ b/script/Interaction.s.sol @@ -4,25 +4,22 @@ pragma solidity ^0.8.18; import {Script, console} from "forge-std/Script.sol"; import {Raffle} from "../src/Raffle.sol"; import {HelperConfig} from "../script/HelperConfig.s.sol"; -import {VRFCoordinatorV2_5Mock} from "chainlink-brownie-contracts/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2_5Mock.sol"; +import {VRFCoordinatorV2_5Mock} from + "chainlink-brownie-contracts/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2_5Mock.sol"; import {LinkToken} from "../test/mock/LinkToken.sol"; import {DevOpsTools} from "lib/foundry-devops/src/DevOpsTools.sol"; contract CreateSubscription is Script { function createSubscriptionUsingConfig() public returns (uint256) { HelperConfig helperConfig = new HelperConfig(); - (, , address vrfCoordinator, , , , ) = helperConfig - .activeNetworkConfig(); + (,, address vrfCoordinator,,,,) = helperConfig.activeNetworkConfig(); return createSubscription(vrfCoordinator); } - function createSubscription( - address vrfCoordinator - ) public returns (uint256 subscriptionId) { + function createSubscription(address vrfCoordinator) public returns (uint256 subscriptionId) { console.log("Creating subscription on Chain:", block.chainid); vm.startBroadcast(); - subscriptionId = VRFCoordinatorV2_5Mock(vrfCoordinator) - .createSubscription(); + subscriptionId = VRFCoordinatorV2_5Mock(vrfCoordinator).createSubscription(); console.log("Your subscriptionId: ", subscriptionId); vm.stopBroadcast(); } @@ -37,40 +34,21 @@ contract FundSubscription is Script { function fundSubscriptionUsingConfig() public { HelperConfig helperConfig = new HelperConfig(); - ( - , - , - address vrfCoordinator, - uint256 subscriptionId, - , - , - address link - ) = helperConfig.activeNetworkConfig(); + (,, address vrfCoordinator, uint256 subscriptionId,,, address link) = helperConfig.activeNetworkConfig(); fundSubscription(vrfCoordinator, subscriptionId, link); } - function fundSubscription( - address vrfCoordinator, - uint256 subscriptionId, - address link - ) public { + function fundSubscription(address vrfCoordinator, uint256 subscriptionId, address link) public { console.log("Funding subscriptionId: ", subscriptionId); console.log("using vrfCoordinator: ", vrfCoordinator); console.log("On chainId: ", block.chainid); if (block.chainid == 31337) { vm.startBroadcast(); - VRFCoordinatorV2_5Mock(vrfCoordinator).fundSubscription( - subscriptionId, - FUND_AMOUNT - ); + VRFCoordinatorV2_5Mock(vrfCoordinator).fundSubscription(subscriptionId, FUND_AMOUNT); vm.stopBroadcast(); } else { vm.startBroadcast(); - LinkToken(link).transferAndCall( - vrfCoordinator, - FUND_AMOUNT, - abi.encode(subscriptionId) - ); + LinkToken(link).transferAndCall(vrfCoordinator, FUND_AMOUNT, abi.encode(subscriptionId)); vm.stopBroadcast(); } } @@ -82,32 +60,17 @@ contract FundSubscription is Script { contract AddConsumer is Script { function run() external { - address raffle = DevOpsTools.get_most_recent_deployment( - "Raffle", - block.chainid - ); + address raffle = DevOpsTools.get_most_recent_deployment("Raffle", block.chainid); addConsumerUsingConfig(raffle); } function addConsumerUsingConfig(address raffle) public { HelperConfig helperConfig = new HelperConfig(); - ( - , - , - address vrfCoordinator, - uint256 subscriptionId, - , - , - - ) = helperConfig.activeNetworkConfig(); + (,, address vrfCoordinator, uint256 subscriptionId,,,) = helperConfig.activeNetworkConfig(); addConsumers(raffle, vrfCoordinator, subscriptionId); } - function addConsumers( - address raffle, - address vrfCoordinator, - uint256 subscriptionId - ) public { + function addConsumers(address raffle, address vrfCoordinator, uint256 subscriptionId) public { console.log("Adding consumer contract: ", raffle); console.log("vrfCoordinator: ", vrfCoordinator); console.log("subscriptionId: ", subscriptionId); diff --git a/src/Raffle.sol b/src/Raffle.sol index 9ae5ede..7e0f975 100644 --- a/src/Raffle.sol +++ b/src/Raffle.sol @@ -8,6 +8,7 @@ import {CCEncoder} from "./tools/CCEncoder.sol"; contract Raffle is VRFConsumerBaseV2Plus, Script { using CCEncoder for bool[]; + uint16 private constant REQUEST_CONFIRMATIONS = 3; uint32 private constant NUM_WORDS = 1; uint256 private constant ROLL_IN_PROGRESS = 42; @@ -31,11 +32,7 @@ contract Raffle is VRFConsumerBaseV2Plus, Script { error Raffle__NotEnoughEtherSent(); error Raffle__WinnerWithdrawFailed(); error Raffle__RaffleStateNotOpen(); - error Raffle__UpKeepNotFeed( - bytes upKeepFlags, - uint256 balance, - uint256 length - ); + error Raffle__UpKeepNotFeed(bytes upKeepFlags, uint256 balance, uint256 length); enum RaffleState { OPEN, @@ -78,9 +75,11 @@ contract Raffle is VRFConsumerBaseV2Plus, Script { * 3.Contract has eth * 4.Subscription is funded with Link */ - function checkUpkeep( - bytes memory /* checkData */ - ) public view returns (bool upkeepNeeded, bytes memory /* performData */) { + function checkUpkeep(bytes memory /* checkData */ ) + public + view + returns (bool upkeepNeeded, bytes memory /* performData */ ) + { bool[] memory flags = new bool[](4); upkeepNeeded = true; @@ -99,14 +98,10 @@ contract Raffle is VRFConsumerBaseV2Plus, Script { return (upkeepNeeded, upKeepFlags); } - function performUpkeep(bytes calldata /* performData */) external { + function performUpkeep(bytes calldata /* performData */ ) external { (bool upkeepNeeded, bytes memory upKeepFlags) = checkUpkeep(""); if (!upkeepNeeded) { - revert Raffle__UpKeepNotFeed( - upKeepFlags, - address(this).balance, - s_players.length - ); + revert Raffle__UpKeepNotFeed(upKeepFlags, address(this).balance, s_players.length); } s_raffleState = RaffleState.CALCULATING; @@ -118,33 +113,29 @@ contract Raffle is VRFConsumerBaseV2Plus, Script { callbackGasLimit: i_callbackGasLimit, numWords: NUM_WORDS, // Set nativePayment to true to pay for VRF requests with Sepolia ETH instead of LINK - extraArgs: VRFV2PlusClient._argsToBytes( - VRFV2PlusClient.ExtraArgsV1({nativePayment: false}) - ) + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: false})) }) ); emit RequestedRaffleWinner(requestId); } - function fulfillRandomWords( - uint256 /* requestId */, - uint256[] calldata randomWords - ) internal virtual override { + function fulfillRandomWords(uint256, /* requestId */ uint256[] calldata randomWords) internal virtual override { uint256 indexOfWinner = randomWords[0] % s_players.length; s_recentWinner = s_players[indexOfWinner]; s_raffleState = RaffleState.OPEN; s_players = new address payable[](0); s_lastTimestamp = block.timestamp; emit WinnerPicked(s_recentWinner); - (bool success, ) = s_recentWinner.call{value: address(this).balance}(""); + (bool success,) = s_recentWinner.call{value: address(this).balance}(""); if (!success) { revert Raffle__WinnerWithdrawFailed(); } } - /**Getter Function */ - + /** + * Getter Function + */ function getEntranceFee() external view returns (uint256) { return i_entranceFee; } diff --git a/src/tools/CCEncoder.sol b/src/tools/CCEncoder.sol index f68cddc..8b22cc8 100644 --- a/src/tools/CCEncoder.sol +++ b/src/tools/CCEncoder.sol @@ -6,18 +6,14 @@ library CCEncoder { output = flag ? bytes("1") : bytes("0"); } - function castFlags( - bool[] memory flags - ) public pure returns (bytes memory output) { + function castFlags(bool[] memory flags) public pure returns (bytes memory output) { output = ""; for (uint256 i = 0; i < flags.length; i++) { output = bytes.concat(output, castFlag(flags[i])); } } - function castFlags( - bool[4] memory flags - ) public pure returns (bytes memory output) { + function castFlags(bool[4] memory flags) public pure returns (bytes memory output) { output = ""; for (uint256 i = 0; i < flags.length; i++) { output = bytes.concat(output, castFlag(flags[i])); diff --git a/test/mock/LinkToken.sol b/test/mock/LinkToken.sol index f2d3589..a9ef30d 100644 --- a/test/mock/LinkToken.sol +++ b/test/mock/LinkToken.sol @@ -52,4 +52,4 @@ contract LinkToken is ERC20 { } return length > 0; } -} \ No newline at end of file +} diff --git a/test/unit/RaffleTest.t.sol b/test/unit/RaffleTest.t.sol index a16aab4..0dd06e3 100644 --- a/test/unit/RaffleTest.t.sol +++ b/test/unit/RaffleTest.t.sol @@ -9,14 +9,16 @@ import {Test, console} from "forge-std/Test.sol"; import {CCEncoder} from "../../src/tools/CCEncoder.sol"; import {Vm} from "forge-std/Vm.sol"; import {CCEncoder} from "~homesrc/tools/CCEncoder.sol"; -import {VRFCoordinatorV2_5Mock} from "chainlink-brownie-contracts/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2_5Mock.sol"; +import {VRFCoordinatorV2_5Mock} from + "chainlink-brownie-contracts/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2_5Mock.sol"; contract RaffleTest is Test { using CCEncoder for bool[]; using CCEncoder for bool[4]; + event EnterRaffle(address indexed player); - event fallbackCalled(address Sender, uint Value, bytes Data); - event Received(address Sender, uint Value); + event fallbackCalled(address Sender, uint256 Value, bytes Data); + event Received(address Sender, uint256 Value); Raffle raffle; HelperConfig helperConfig; @@ -33,6 +35,7 @@ contract RaffleTest is Test { _; vm.stopPrank(); } + modifier M_prankPlayer() { vm.prank(PlayerAddress); _; @@ -61,8 +64,7 @@ contract RaffleTest is Test { DeployRaffle deployRaffle = new DeployRaffle(); (raffle, helperConfig) = deployRaffle.run(); vm.deal(PlayerAddress, STARTING_USER_BALANCE); - (entranceFee, interval, vrfCoordinator, , , , ) = helperConfig - .activeNetworkConfig(); + (entranceFee, interval, vrfCoordinator,,,,) = helperConfig.activeNetworkConfig(); } function testRaffleInitializesInOpenState() public view { @@ -75,66 +77,40 @@ contract RaffleTest is Test { raffle.enterRaffle(); } - function testRaffleRecordsPlayerWhenTheyEnter() - public - M_startPrankPlayer - M_enterRaffle - { + function testRaffleRecordsPlayerWhenTheyEnter() public M_startPrankPlayer M_enterRaffle { address addressFromRaffle = raffle.getIndexedPlayer(0); assertEq(addressFromRaffle, PlayerAddress); } - function testEmitsEventOnEntrance() - public - M_startPrankPlayer - M_enterRaffle - { + function testEmitsEventOnEntrance() public M_startPrankPlayer M_enterRaffle { vm.expectEmit(true, false, false, false, address(raffle)); emit EnterRaffle(PlayerAddress); raffle.enterRaffle{value: entranceFee}(); } - function testCantEnterWhenRaffleIsCalculating() - public - M_startPrankPlayer - M_enterRaffle - M_timePassed - { + function testCantEnterWhenRaffleIsCalculating() public M_startPrankPlayer M_enterRaffle M_timePassed { raffle.performUpkeep(""); vm.expectRevert(Raffle.Raffle__RaffleStateNotOpen.selector); raffle.enterRaffle{value: entranceFee}(); } - function testCheckUpkeepReturnsFalseIfItHasNoBalance() - public - M_startPrankPlayer - M_timePassed - { + function testCheckUpkeepReturnsFalseIfItHasNoBalance() public M_startPrankPlayer M_timePassed { // raffle.enterRaffle(); - (bool upKeepNeeded, ) = raffle.checkUpkeep(""); + (bool upKeepNeeded,) = raffle.checkUpkeep(""); assert(!upKeepNeeded); } - function testCheckUpkeepReturnsFalseIfRaffleNotOpen() - public - M_startPrankPlayer - M_enterRaffle - M_timePassed - { + function testCheckUpkeepReturnsFalseIfRaffleNotOpen() public M_startPrankPlayer M_enterRaffle M_timePassed { raffle.performUpkeep(""); - (bool upkeepFlag, ) = raffle.checkUpkeep(""); + (bool upkeepFlag,) = raffle.checkUpkeep(""); assert(!upkeepFlag); } - function testCheckUpkeepReturnsFalseIfEnoughTimeHasNotPassed() - public - M_startPrankPlayer - M_enterRaffle - { + function testCheckUpkeepReturnsFalseIfEnoughTimeHasNotPassed() public M_startPrankPlayer M_enterRaffle { vm.warp(block.timestamp + 1); vm.roll(block.number + 1); bool[4] memory inputflags = [false, true, true, true]; @@ -145,12 +121,7 @@ contract RaffleTest is Test { assertEq(upKeepFlags, flags); } - function testCheckUpkeepReturnsFalseIfStateNotOpen() - public - M_startPrankPlayer - M_enterRaffle - M_timePassed - { + function testCheckUpkeepReturnsFalseIfStateNotOpen() public M_startPrankPlayer M_enterRaffle M_timePassed { bool[4] memory inputflags = [true, false, true, true]; bytes memory upKeepFlags = inputflags.castFlags(); raffle.performUpkeep(""); @@ -160,12 +131,7 @@ contract RaffleTest is Test { assertEq(upKeepFlags, flags); } - function testCheckUpkeepReturnsFalseIfBalanceZero() - public - M_startPrankPlayer - M_enterRaffle - M_timePassed - { + function testCheckUpkeepReturnsFalseIfBalanceZero() public M_startPrankPlayer M_enterRaffle M_timePassed { vm.deal(address(raffle), 0); bool[4] memory inputflags = [true, true, false, true]; @@ -176,11 +142,7 @@ contract RaffleTest is Test { assertEq(upKeepFlags, flags); } - function testCheckUpkeepReturnsFalseIfNoPlayer() - public - M_startPrankPlayer - M_timePassed - { + function testCheckUpkeepReturnsFalseIfNoPlayer() public M_startPrankPlayer M_timePassed { vm.deal(address(raffle), 1 ether); bool[4] memory inputflags = [true, true, true, false]; bytes memory upKeepFlags = inputflags.castFlags(); @@ -190,51 +152,28 @@ contract RaffleTest is Test { assertEq(upKeepFlags, flags); } - function testCheckUpkeepReturnsTrueWhenParametersAreGood() - public - M_startPrankPlayer - M_enterRaffle - M_timePassed - { - (bool upkeepNeeded, ) = raffle.checkUpkeep(""); + function testCheckUpkeepReturnsTrueWhenParametersAreGood() public M_startPrankPlayer M_enterRaffle M_timePassed { + (bool upkeepNeeded,) = raffle.checkUpkeep(""); assert(upkeepNeeded); } - function testPerformUpkeepCanOnlyRunIfCheckUpkeepIsTrue() - public - M_startPrankPlayer - M_enterRaffle - M_timePassed - { + function testPerformUpkeepCanOnlyRunIfCheckUpkeepIsTrue() public M_startPrankPlayer M_enterRaffle M_timePassed { raffle.performUpkeep(""); } - function testPerformUpkeepRevertsIfCheckUpkeepIsFalse() - public - M_startPrankPlayer - M_enterRaffle - { + function testPerformUpkeepRevertsIfCheckUpkeepIsFalse() public M_startPrankPlayer M_enterRaffle { vm.warp(block.timestamp + 1); vm.roll(block.number + 1); bool[4] memory inputflags = [false, true, true, true]; bytes memory upKeepFlags = inputflags.castFlags(); - bytes memory expectedRevertData = abi.encodeWithSelector( - Raffle.Raffle__UpKeepNotFeed.selector, - upKeepFlags, - address(raffle).balance, - 1 - ); + bytes memory expectedRevertData = + abi.encodeWithSelector(Raffle.Raffle__UpKeepNotFeed.selector, upKeepFlags, address(raffle).balance, 1); vm.expectRevert(expectedRevertData); raffle.performUpkeep(""); } - function testPerformUpkeepUpdateRaffleStateAndEmitsRequestId() - public - M_enterRaffle - M_enterRaffle - M_timePassed - { + function testPerformUpkeepUpdateRaffleStateAndEmitsRequestId() public M_enterRaffle M_enterRaffle M_timePassed { vm.recordLogs(); raffle.performUpkeep(""); Vm.Log[] memory entries = vm.getRecordedLogs(); @@ -258,11 +197,7 @@ contract RaffleTest is Test { uint256 additionalEntrances = 3; uint256 startingIndex = 1; // We have starting index be 1 so we can start with address(1) and not address(0) - for ( - uint256 i = startingIndex; - i < startingIndex + additionalEntrances; - i++ - ) { + for (uint256 i = startingIndex; i < startingIndex + additionalEntrances; i++) { address player = address(uint160(i)); hoax(player, STARTING_USER_BALANCE); // deal 1 eth to the player raffle.enterRaffle{value: entranceFee}(); @@ -279,10 +214,7 @@ contract RaffleTest is Test { console.log(address(raffle).balance); - VRFCoordinatorV2_5Mock(vrfCoordinator).fulfillRandomWords( - uint256(requestId), - address(raffle) - ); + VRFCoordinatorV2_5Mock(vrfCoordinator).fulfillRandomWords(uint256(requestId), address(raffle)); // Assert address recentWinner = raffle.getRecentWinner(); @@ -327,13 +259,9 @@ contract ToolTest is Test { flags[2] = false; flags[3] = false; - assertEq( - flags.castFlags(), - bytes.concat(bytes("1"), bytes("0"), bytes("0"), bytes("0")) - ); + assertEq(flags.castFlags(), bytes.concat(bytes("1"), bytes("0"), bytes("0"), bytes("0"))); } - //3way to get a function's selector (case1's 'this' can be replace to a instance of a contract); function testEncoderWithSelector() public view { bytes4 output1 = this.testCastMultiFlag.selector;