Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: initial structure for covering all key scenarios #1

Merged
merged 9 commits into from
Aug 28, 2024
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im guessing formally reverting it will prevent chainlink from making the actual call, and thus saving gas?


// 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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getModules() is limited to the first ten modules in the list, but i think that should be fine for now

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