Skip to content

Commit

Permalink
Merge pull request #1 from onchainification/feat/tests
Browse files Browse the repository at this point in the history
test: initial structure for covering all key scenarios
  • Loading branch information
petrovska-petro authored Aug 28, 2024
2 parents d319b49 + 4e38534 commit c536cb7
Show file tree
Hide file tree
Showing 7 changed files with 393 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name: CI

on:
push:
pull_request:
workflow_dispatch:

env:
FOUNDRY_PROFILE: ci
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}

jobs:
check:
Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "solidity.formatter": "forge" }
29 changes: 25 additions & 4 deletions src/AuraLockerModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ contract AuraLockerModule is
CONSTANTS
//////////////////////////////////////////////////////////////////////////*/
address public constant BALANCER_MULTISIG = 0x10A19e7eE7d7F8a52822f6817de8ea18204F2e4f;
IGnosisSafe public constant SAFE = IGnosisSafe(BALANCER_MULTISIG);
IGnosisSafe public constant SAFE = IGnosisSafe(payable(BALANCER_MULTISIG));

IERC20 public constant AURA = IERC20(0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF);

Expand All @@ -34,13 +34,16 @@ contract AuraLockerModule is
ERRORS
//////////////////////////////////////////////////////////////////////////*/
error NotKeeper(address agent);
error NotGovernance(address agent);

error ZeroAddressValue();

error ModuleNotEnabled();

error TxFromModuleFailed();

error NothingToLock(uint256 timestamp);

/*//////////////////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////////////////*/
Expand All @@ -61,13 +64,19 @@ contract AuraLockerModule is
_;
}

/// @notice Enforce that the function is called by governance only
modifier onlyGovernance() {
if (msg.sender != BALANCER_MULTISIG) revert NotGovernance(msg.sender);
_;
}

/*//////////////////////////////////////////////////////////////////////////
EXTERNAL METHODS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Assigns a new keeper address
/// @param _keeper The address of the new keeper
function setKeeper(address _keeper) external {
function setKeeper(address _keeper) external onlyGovernance {
if (_keeper == address(0)) revert ZeroAddressValue();

address oldKeeper = keeper;
Expand All @@ -85,7 +94,7 @@ contract AuraLockerModule is
override
returns (bool requiresLocking, bytes memory execPayload)
{
if (!SAFE.isModuleEnabled(address(this))) return (false, bytes("AuraLocker module is not enabled"));
if (!_isModuleEnabled()) return (false, bytes("AuraLocker module is not enabled"));

(, uint256 unlockable,,) = AURA_LOCKER.lockedBalances(address(SAFE));

Expand All @@ -98,7 +107,10 @@ contract AuraLockerModule is

/// @notice The actual execution of the action determined by the `checkUpkeep` method (AURA locking)
function performUpkeep(bytes calldata /* _performData */ ) external override onlyKeeper {
if (!SAFE.isModuleEnabled(address(this))) revert ModuleNotEnabled();
if (!_isModuleEnabled()) revert ModuleNotEnabled();

(, uint256 unlockable,,) = AURA_LOCKER.lockedBalances(address(SAFE));
if (unlockable == 0) revert NothingToLock(block.timestamp);

// execute: `processExpiredLocks` via module
if (
Expand All @@ -107,4 +119,13 @@ contract AuraLockerModule is
)
) revert TxFromModuleFailed();
}

/// @dev The Gnosis Safe version 1.1.1 does not expose directly `isModuleEnabled` method, so we need a workaround
function _isModuleEnabled() internal view returns (bool) {
address[] memory modules = SAFE.getModules();
for (uint256 i = 0; i < modules.length; i++) {
if (modules[i] == address(this)) return true;
}
return false;
}
}
109 changes: 109 additions & 0 deletions src/interfaces/chainlink/IKeeperRegistrar.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

interface IKeeperRegistrar {
type AutoApproveType is uint8;

struct InitialTriggerConfig {
uint8 triggerType;
AutoApproveType autoApproveType;
uint32 autoApproveMaxAllowed;
}

struct RegistrationParams {
string name;
bytes encryptedEmail;
address upkeepContract;
uint32 gasLimit;
address adminAddress;
uint8 triggerType;
bytes checkData;
bytes triggerConfig;
bytes offchainConfig;
uint96 amount;
}

struct TriggerRegistrationStorage {
AutoApproveType autoApproveType;
uint32 autoApproveMaxAllowed;
uint32 approvedCount;
}

error AmountMismatch();
error FunctionNotPermitted();
error HashMismatch();
error InsufficientPayment();
error InvalidAdminAddress();
error InvalidDataLength();
error LinkTransferFailed(address to);
error OnlyAdminOrOwner();
error OnlyLink();
error RegistrationRequestFailed();
error RequestNotFound();
error SenderMismatch();

event AutoApproveAllowedSenderSet(address indexed senderAddress, bool allowed);
event ConfigChanged(address keeperRegistry, uint96 minLINKJuels);
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
event RegistrationApproved(bytes32 indexed hash, string displayName, uint256 indexed upkeepId);
event RegistrationRejected(bytes32 indexed hash);
event RegistrationRequested(
bytes32 indexed hash,
string name,
bytes encryptedEmail,
address indexed upkeepContract,
uint32 gasLimit,
address adminAddress,
uint8 triggerType,
bytes triggerConfig,
bytes offchainConfig,
bytes checkData,
uint96 amount
);
event TriggerConfigSet(uint8 triggerType, AutoApproveType autoApproveType, uint32 autoApproveMaxAllowed);

function LINK() external view returns (address);
function acceptOwnership() external;
function approve(
string memory name,
address upkeepContract,
uint32 gasLimit,
address adminAddress,
uint8 triggerType,
bytes memory checkData,
bytes memory triggerConfig,
bytes memory offchainConfig,
bytes32 hash
) external;
function cancel(bytes32 hash) external;
function getAutoApproveAllowedSender(address senderAddress) external view returns (bool);
function getConfig() external view returns (address keeperRegistry, uint256 minLINKJuels);
function getPendingRequest(bytes32 hash) external view returns (address, uint96);
function getTriggerRegistrationDetails(uint8 triggerType)
external
view
returns (TriggerRegistrationStorage memory);
function onTokenTransfer(address sender, uint256 amount, bytes memory data) external;
function owner() external view returns (address);
function register(
string memory name,
bytes memory encryptedEmail,
address upkeepContract,
uint32 gasLimit,
address adminAddress,
uint8 triggerType,
bytes memory checkData,
bytes memory triggerConfig,
bytes memory offchainConfig,
uint96 amount,
address sender
) external;
function registerUpkeep(RegistrationParams memory requestParams) external returns (uint256);
function setAutoApproveAllowedSender(address senderAddress, bool allowed) external;
function setConfig(address keeperRegistry, uint96 minLINKJuels) external;
function setTriggerConfig(uint8 triggerType, AutoApproveType autoApproveType, uint32 autoApproveMaxAllowed)
external;
function transferOwnership(address to) external;
function typeAndVersion() external view returns (string memory);
}
109 changes: 93 additions & 16 deletions src/interfaces/gnosis/IGnosisSafe.sol
Original file line number Diff line number Diff line change
@@ -1,29 +1,106 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
pragma solidity ^0.8.4;

interface IGnosisSafe {
event DisabledModule(address module);
event EnabledModule(address module);

enum Operation {
Call,
DelegateCall
}

/// @dev Allows a Module to execute a Safe transaction without any further confirmations.
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction.
function execTransactionFromModule(address to, uint256 value, bytes calldata data, Operation operation)
external
returns (bool success);
event AddedOwner(address owner);
event ApproveHash(bytes32 indexed approvedHash, address indexed owner);
event ChangedMasterCopy(address masterCopy);
event ChangedThreshold(uint256 threshold);
event DisabledModule(address module);
event EnabledModule(address module);
event ExecutionFailure(bytes32 txHash, uint256 payment);
event ExecutionFromModuleFailure(address indexed module);
event ExecutionFromModuleSuccess(address indexed module);
event ExecutionSuccess(bytes32 txHash, uint256 payment);
event RemovedOwner(address owner);
event SignMsg(bytes32 indexed msgHash);

function enableModule(address module) external;
fallback() external payable;

function NAME() external view returns (string memory);
function VERSION() external view returns (string memory);
function addOwnerWithThreshold(address owner, uint256 _threshold) external;
function approveHash(bytes32 hashToApprove) external;
function approvedHashes(address, bytes32) external view returns (uint256);
function changeMasterCopy(address _masterCopy) external;
function changeThreshold(uint256 _threshold) external;
function disableModule(address prevModule, address module) external;

function domainSeparator() external view returns (bytes32);
function enableModule(address module) external;
function encodeTransactionData(
address to,
uint256 value,
bytes memory data,
Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) external view returns (bytes memory);
function execTransaction(
address to,
uint256 value,
bytes memory data,
Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver,
bytes memory signatures
) external returns (bool success);
function execTransactionFromModule(address to, uint256 value, bytes memory data, Operation operation)
external
returns (bool success);
function execTransactionFromModuleReturnData(address to, uint256 value, bytes memory data, Operation operation)
external
returns (bool success, bytes memory returnData);
function getMessageHash(bytes memory message) external view returns (bytes32);
function getModules() external view returns (address[] memory);

function isModuleEnabled(address module) external view returns (bool);
function getModulesPaginated(address start, uint256 pageSize)
external
view
returns (address[] memory array, address next);
function getOwners() external view returns (address[] memory);
function getThreshold() external view returns (uint256);
function getTransactionHash(
address to,
uint256 value,
bytes memory data,
Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) external view returns (bytes32);
function isOwner(address owner) external view returns (bool);
function isValidSignature(bytes memory _data, bytes memory _signature) external returns (bytes4);
function nonce() external view returns (uint256);
function removeOwner(address prevOwner, address owner, uint256 _threshold) external;
function requiredTxGas(address to, uint256 value, bytes memory data, Operation operation)
external
returns (uint256);
function setFallbackHandler(address handler) external;
function setup(
address[] memory _owners,
uint256 _threshold,
address to,
bytes memory data,
address fallbackHandler,
address paymentToken,
uint256 payment,
address payable paymentReceiver
) external;
function signMessage(bytes memory _data) external;
function signedMessages(bytes32) external view returns (uint256);
function swapOwner(address prevOwner, address oldOwner, address newOwner) external;
}
Loading

0 comments on commit c536cb7

Please sign in to comment.