Skip to content

Commit

Permalink
(test): Add ToS Allow List foundry tests (#10438)
Browse files Browse the repository at this point in the history
* (test): Add Functions Subscriptions foundry tests

* (test): Add ToS Allow List foundry tests
  • Loading branch information
justinkaseman authored Sep 6, 2023
1 parent e5487f0 commit a7dc6f1
Show file tree
Hide file tree
Showing 2 changed files with 325 additions and 13 deletions.
25 changes: 23 additions & 2 deletions contracts/gas-snapshots/functions.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSub
FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20103)
FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 193421)
FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_Success() (gas: 67209)
FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7609)
FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7609)
FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28659)
FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17970)
FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 371776)
Expand Down Expand Up @@ -88,4 +88,25 @@ FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest
FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57781)
FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26368)
FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15714)
FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152510)
FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152510)
FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25855)
FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 44366)
FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23615)
FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1469094)
FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26021)
FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1549182)
FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 94702)
FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15469)
FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 50442)
FunctionsTermsOfServiceAllowList_Constructor:test_Constructor_Success() (gas: 12187)
FunctionsTermsOfServiceAllowList_GetAllAllowedSenders:test_GetAllAllowedSenders_Success() (gas: 19243)
FunctionsTermsOfServiceAllowList_GetConfig:test_GetConfig_Success() (gas: 15773)
FunctionsTermsOfServiceAllowList_GetMessage:test_GetMessage_Success() (gas: 11592)
FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_FalseWhenEnabled() (gas: 15931)
FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_TrueWhenDisabled() (gas: 23445)
FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessFalse() (gas: 15354)
FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessTrue() (gas: 41957)
FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_RevertIfNotOwner() (gas: 13525)
FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas: 95208)
FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13736)
FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22082)
Original file line number Diff line number Diff line change
@@ -1,52 +1,343 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/// @notice #constructor
contract FunctionsTermsOfServiceAllowList_Constructor {
import {TermsOfServiceAllowList} from "../../dev/1_0_0/accessControl/TermsOfServiceAllowList.sol";
import {FunctionsClientTestHelper} from "./testhelpers/FunctionsClientTestHelper.sol";

import {FunctionsRoutesSetup, FunctionsOwnerAcceptTermsOfServiceSetup} from "./Setup.t.sol";

/// @notice #constructor
contract FunctionsTermsOfServiceAllowList_Constructor is FunctionsRoutesSetup {
function test_Constructor_Success() public {
assertEq(s_termsOfServiceAllowList.typeAndVersion(), "Functions Terms of Service Allow List v1.0.0");
assertEq(s_termsOfServiceAllowList.owner(), OWNER_ADDRESS);
}
}

/// @notice #getConfig
contract FunctionsTermsOfServiceAllowList_GetConfig {
contract FunctionsTermsOfServiceAllowList_GetConfig is FunctionsRoutesSetup {
function test_GetConfig_Success() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

TermsOfServiceAllowList.Config memory config = s_termsOfServiceAllowList.getConfig();
assertEq(config.enabled, getTermsOfServiceConfig().enabled);
assertEq(config.signerPublicKey, getTermsOfServiceConfig().signerPublicKey);
}
}

/// @notice #updateConfig
contract FunctionsTermsOfServiceAllowList_UpdateConfig {
contract FunctionsTermsOfServiceAllowList_UpdateConfig is FunctionsRoutesSetup {
function test_UpdateConfig_RevertIfNotOwner() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

vm.expectRevert("Only callable by owner");
s_termsOfServiceAllowList.updateConfig(
TermsOfServiceAllowList.Config({enabled: true, signerPublicKey: STRANGER_ADDRESS})
);
}

event ConfigUpdated(TermsOfServiceAllowList.Config config);

function test_UpdateConfig_Success() public {
TermsOfServiceAllowList.Config memory configToSet = TermsOfServiceAllowList.Config({
enabled: false,
signerPublicKey: TOS_SIGNER
});

// topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true).
bool checkTopic1 = false;
bool checkTopic2 = false;
bool checkTopic3 = false;
bool checkData = true;
vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);
emit ConfigUpdated(configToSet);

s_termsOfServiceAllowList.updateConfig(configToSet);

TermsOfServiceAllowList.Config memory config = s_termsOfServiceAllowList.getConfig();
assertEq(config.enabled, configToSet.enabled);
assertEq(config.signerPublicKey, configToSet.signerPublicKey);
}
}

/// @notice #getMessage
contract FunctionsTermsOfServiceAllowList_GetMessage {
contract FunctionsTermsOfServiceAllowList_GetMessage is FunctionsRoutesSetup {
function test_GetMessage_Success() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS);

assertEq(message, keccak256(abi.encodePacked(STRANGER_ADDRESS, STRANGER_ADDRESS)));
}
}

/// @notice #acceptTermsOfService
contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService {
contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService is FunctionsRoutesSetup {
function test_AcceptTermsOfService_RevertIfBlockedSender() public {
s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS);

// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS);
bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage);

vm.expectRevert(TermsOfServiceAllowList.RecipientIsBlocked.selector);

s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v);
}

function test_AcceptTermsOfService_RevertIfInvalidSigner() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS);
bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(STRANGER_PRIVATE_KEY, prefixedMessage);

vm.expectRevert(TermsOfServiceAllowList.InvalidSignature.selector);

s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v);
}

function test_AcceptTermsOfService_RevertIfRecipientIsNotSender() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

bytes32 message = s_termsOfServiceAllowList.getMessage(OWNER_ADDRESS, STRANGER_ADDRESS);
bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage);

vm.expectRevert(TermsOfServiceAllowList.InvalidUsage.selector);

s_termsOfServiceAllowList.acceptTermsOfService(OWNER_ADDRESS, STRANGER_ADDRESS, r, s, v);
}

function test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, OWNER_ADDRESS);
bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage);

vm.expectRevert(TermsOfServiceAllowList.InvalidUsage.selector);

s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, OWNER_ADDRESS, r, s, v);
}

function test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() public {
FunctionsClientTestHelper s_functionsClientHelper = new FunctionsClientTestHelper(address(s_functionsRouter));

// Send as externally owned account
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

// Attempt to accept for a contract account
bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, address(s_functionsClientHelper));
bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage);

vm.expectRevert(TermsOfServiceAllowList.InvalidUsage.selector);

s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, address(s_functionsClientHelper), r, s, v);
}

event AddedAccess(address user);

function test_AcceptTermsOfService_SuccessIfAcceptingForSelf() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS);
bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage);

// topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true).
bool checkTopic1 = false;
bool checkTopic2 = false;
bool checkTopic3 = false;
bool checkData = true;
vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);
emit AddedAccess(STRANGER_ADDRESS);

s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v);

assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), true);
}

function test_AcceptTermsOfService_SuccessIfAcceptingForContract() public {
FunctionsClientTestHelper s_functionsClientHelper = new FunctionsClientTestHelper(address(s_functionsRouter));

// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, address(s_functionsClientHelper));
bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage);

// topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true).
bool checkTopic1 = false;
bool checkTopic2 = false;
bool checkTopic3 = false;
bool checkData = true;
vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);
emit AddedAccess(address(s_functionsClientHelper));

s_functionsClientHelper.acceptTermsOfService(STRANGER_ADDRESS, address(s_functionsClientHelper), r, s, v);

assertEq(s_termsOfServiceAllowList.hasAccess(address(s_functionsClientHelper), new bytes(0)), true);
}
}

/// @notice #getAllAllowedSenders
contract FunctionsTermsOfServiceAllowList_GetAllAllowedSenders {
contract FunctionsTermsOfServiceAllowList_GetAllAllowedSenders is FunctionsOwnerAcceptTermsOfServiceSetup {
function test_GetAllAllowedSenders_Success() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

address[] memory expectedSenders = new address[](1);
expectedSenders[0] = OWNER_ADDRESS;

assertEq(s_termsOfServiceAllowList.getAllAllowedSenders(), expectedSenders);
}
}

/// @notice #hasAccess
contract FunctionsTermsOfServiceAllowList_HasAccess {
contract FunctionsTermsOfServiceAllowList_HasAccess is FunctionsRoutesSetup {
function test_HasAccess_FalseWhenEnabled() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

// Check access of account that is not on the allow list
assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), false);
}

function test_HasAccess_TrueWhenDisabled() public {
// Disable allow list, which opens all access
s_termsOfServiceAllowList.updateConfig(
TermsOfServiceAllowList.Config({enabled: false, signerPublicKey: TOS_SIGNER})
);

// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

// Check access of account that is not on the allow list
assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), true);
}
}

/// @notice #isBlockedSender
contract FunctionsTermsOfServiceAllowList_IsBlockedSender {
contract FunctionsTermsOfServiceAllowList_IsBlockedSender is FunctionsRoutesSetup {
function test_IsBlockedSender_SuccessFalse() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

assertEq(s_termsOfServiceAllowList.isBlockedSender(STRANGER_ADDRESS), false);
}

function test_IsBlockedSender_SuccessTrue() public {
// Block sender
s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS);

// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

assertEq(s_termsOfServiceAllowList.isBlockedSender(STRANGER_ADDRESS), true);
}
}

/// @notice #blockSender
contract FunctionsTermsOfServiceAllowList_BlockSender {
contract FunctionsTermsOfServiceAllowList_BlockSender is FunctionsRoutesSetup {
function test_BlockSender_RevertIfNotOwner() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

vm.expectRevert("Only callable by owner");
s_termsOfServiceAllowList.blockSender(OWNER_ADDRESS);
}

event BlockedAccess(address user);

function test_BlockSender_Success() public {
// topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true).
bool checkTopic1 = false;
bool checkTopic2 = false;
bool checkTopic3 = false;
bool checkData = true;
vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);
emit BlockedAccess(STRANGER_ADDRESS);

s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS);
assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), false);
assertEq(s_termsOfServiceAllowList.isBlockedSender(STRANGER_ADDRESS), true);

// Account can no longer accept Terms of Service
bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS);
bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage);
vm.expectRevert(TermsOfServiceAllowList.RecipientIsBlocked.selector);
s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v);
}
}

/// @notice #unblockSender
contract FunctionsTermsOfServiceAllowList_UnblockSender {
contract FunctionsTermsOfServiceAllowList_UnblockSender is FunctionsRoutesSetup {
function setUp() public virtual override {
FunctionsRoutesSetup.setUp();

s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS);
}

function test_UnblockSender_RevertIfNotOwner() public {
// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

vm.expectRevert("Only callable by owner");
s_termsOfServiceAllowList.unblockSender(STRANGER_ADDRESS);
}

event UnblockedAccess(address user);

function test_UnblockSender_Success() public {
// topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true).
bool checkTopic1 = false;
bool checkTopic2 = false;
bool checkTopic3 = false;
bool checkData = true;
vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);
emit UnblockedAccess(STRANGER_ADDRESS);

s_termsOfServiceAllowList.unblockSender(STRANGER_ADDRESS);

// Send as stranger
vm.stopPrank();
vm.startPrank(STRANGER_ADDRESS);

// Account can now accept the Terms of Service
bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS);
bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage);
s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v);
}
}

0 comments on commit a7dc6f1

Please sign in to comment.