This report was generated by Aderyn, a static analysis tool built by Cyfrin, a blockchain security company. This report is not a substitute for manual audit or security review. It should not be relied upon for any purpose other than to assist in the identification of potential security vulnerabilities.
- Aderyn Analysis Report
- Table of Contents
- Summary
- High Issues
- Low Issues
- L-1: Centralization Risk for trusted owners
- L-2: Unsafe ERC20 Operations should not be used
- L-3: Missing checks for
address(0)
when assigning values to address state variables - L-4:
public
functions not used internally could be markedexternal
- L-5: Define and use
constant
variables instead of using literals - L-6: Event is missing
indexed
fields - L-7: Modifiers invoked only once can be shoe-horned into the function
- L-8: Large literal values multiples of 10000 can be replaced with scientific notation
- L-9: Internal functions called only once can be inlined
- L-10: Unused Custom Error
- L-11: Loop condition contains
state_variable.length
that could be cached outside. - L-12: Unused Imports
- L-13: State variable could be declared constant
- L-14: State variable changes but no event is emitted.
- L-15: State variable could be declared immutable
Key | Value |
---|---|
.sol Files | 7 |
Total nSLOC | 822 |
Filepath | nSLOC |
---|---|
src/CheckBalance.sol | 127 |
src/Receiver.sol | 250 |
src/Relayer.sol | 82 |
src/Sender.sol | 85 |
src/Subscription.sol | 247 |
src/interfaces/ILogAutomation.sol | 18 |
src/library/ReceiverSignedMessage.sol | 13 |
Total | 822 |
Category | No. of Issues |
---|---|
High | 4 |
Low | 15 |
Passing an arbitrary from
address to transferFrom
(or safeTransferFrom
) can lead to loss of funds, because anyone can transfer tokens from the from
address if an approval is made.
1 Found Instances
-
Found in src/Receiver.sol Line: 247
IERC20(signedMessage.token).safeTransferFrom(
Consider introducing checks for msg.sender
to ensure the recipient of the money is as intended.
1 Found Instances
-
Found in src/Subscription.sol Line: 264
function withdraw() external onlyOwner {
Function returns a value but it is ignored.
5 Found Instances
-
Found in src/Receiver.sol Line: 254
transferTokensPayLINK(
-
Found in src/Relayer.sol Line: 81
sendMessage(i_subscriptionAddress, performData);
-
Found in src/Subscription.sol Line: 318
checkBalance.sendRequest(true, AMOY_SUBSCRIPTION_ID, args);
-
Found in src/Subscription.sol Line: 321
checkBalance.sendRequest(false, AMOY_SUBSCRIPTION_ID, args);
-
Found in src/Subscription.sol Line: 329
s_sender.sendMessage(optionalChain, i_receiver, signedMessage);
It appears that the contract includes a payable function to accept Ether but lacks a corresponding function to withdraw it, which leads to the Ether being locked in the contract. To resolve this issue, please implement a public or external function that allows for the withdrawal of Ether from the contract.
1 Found Instances
-
Found in src/Receiver.sol Line: 18
contract Receiver is CCIPReceiver, EIP712, OwnerIsCreator {
Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.
10 Found Instances
-
Found in src/CheckBalance.sol Line: 13
contract CheckBalance is FunctionsClient, Ownable {
-
Found in src/CheckBalance.sol Line: 107
) external onlyOwner initializedOnlyOnce {
-
Found in src/CheckBalance.sol Line: 120
) external onlyOwner hasInitialized returns (bytes32 requestId) {
-
Found in src/Receiver.sol Line: 134
) public onlyOwner {
-
Found in src/Sender.sol Line: 13
contract Sender is Ownable {
-
Found in src/Sender.sol Line: 85
) external onlyOwner initializedOnlyOnce {
-
Found in src/Sender.sol Line: 99
) external onlyOwner hasInitialized returns (bytes32 messageId) {
-
Found in src/Subscription.sol Line: 20
contract Subscription is ILogAutomation, CCIPReceiver, Ownable {
-
Found in src/Subscription.sol Line: 264
function withdraw() external onlyOwner {
-
Found in src/Subscription.sol Line: 273
function withdrawToken(address token) external onlyOwner {
ERC20 functions may not behave as expected. For example: return values are not always meaningful. It is recommended to use OpenZeppelin's SafeERC20 library.
5 Found Instances
-
Found in src/Receiver.sol Line: 176
s_linkToken.approve(address(s_router), fees);
-
Found in src/Receiver.sol Line: 179
IERC20(_token).approve(address(s_router), _amount);
-
Found in src/Relayer.sol Line: 121
s_linkToken.approve(address(s_router), fees);
-
Found in src/Sender.sol Line: 132
s_linkToken.approve(address(s_router), fees);
-
Found in src/Subscription.sol Line: 242
token.approve(address(this), SUBSCRIPTION_FEE);
Check for address(0)
when assigning values to address state variables.
11 Found Instances
-
Found in src/Receiver.sol Line: 110
s_router = IRouterClient(_router);
-
Found in src/Receiver.sol Line: 111
s_linkToken = IERC20(_link);
-
Found in src/Relayer.sol Line: 55
s_router = IRouterClient(_router);
-
Found in src/Relayer.sol Line: 56
s_linkToken = LinkTokenInterface(_link);
-
Found in src/Sender.sol Line: 74
s_router = IRouterClient(_router);
-
Found in src/Sender.sol Line: 75
s_linkToken = LinkTokenInterface(_link);
-
Found in src/Subscription.sol Line: 88
s_allowedToken = _allowedToken;
-
Found in src/Subscription.sol Line: 89
s_allowedTokenForOptionalChain = _allowedTokenForOptionalChain;
-
Found in src/Subscription.sol Line: 90
s_router = IRouterClient(_router);
-
Found in src/Subscription.sol Line: 91
s_sepoliaCheckBalanceAddress = _sepoliaCheckBalanceAddress;
-
Found in src/Subscription.sol Line: 92
s_sender = Sender(_sender);
Instead of marking a function as public
, consider marking it as external
if it is not used internally.
3 Found Instances
If the same constant literal value is used multiple times, create a constant state variable and reference it throughout the contract.
2 Found Instances
Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields). Each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.
7 Found Instances
-
Found in src/CheckBalance.sol Line: 64
event Response(
-
Found in src/Receiver.sol Line: 76
event TokensTransferred(
-
Found in src/Receiver.sol Line: 86
event NonceUpdated(address indexed subscriber, uint256 nonce);
-
Found in src/Relayer.sol Line: 38
event MessageSent(
-
Found in src/Sender.sol Line: 39
event MessageSent(
-
Found in src/Subscription.sol Line: 55
event SubscriberToSubscriptionUpdated(
-
Found in src/Subscription.sol Line: 62
event Withdrawn(address token, uint256 amount);
5 Found Instances
-
Found in src/CheckBalance.sol Line: 75
modifier initializedOnlyOnce() {
-
Found in src/CheckBalance.sol Line: 82
modifier hasInitialized() {
-
Found in src/Receiver.sol Line: 94
modifier validateReceiver(address _receiver) {
-
Found in src/Sender.sol Line: 52
modifier initializedOnlyOnce() {
-
Found in src/Sender.sol Line: 59
modifier hasInitialized() {
Use e
notation, for example: 1e18
, instead of its full numeric value.
3 Found Instances
Instead of separating the logic into a separate function, consider inlining the logic into the calling function. This can reduce the number of function calls and improve readability.
2 Found Instances
it is recommended that the definition be removed when custom error is unused
2 Found Instances
Cache the lengths of storage arrays if they are used and not modified in for loops.
1 Found Instances
-
Found in src/Subscription.sol Line: 287
for (uint256 i = 0; i < s_subscriptionChainsSelector.length; i++) {
Redundant import statement. Consider removing it.
1 Found Instances
-
Found in src/Subscription.sol Line: 11
import {Client} from "@chainlink/contracts/src/v0.8/ccip/libraries/Client.sol";
State variables that are not updated following deployment should be declared constant to save gas. Add the constant
attribute to state variables that never change.
2 Found Instances
State variable changes in this function but no event is emitted.
3 Found Instances
State variables that are should be declared immutable to save gas. Add the immutable
attribute to state variables that are only changed in the constructor
13 Found Instances
-
Found in src/CheckBalance.sol Line: 24
bytes32 private s_donID;
-
Found in src/Receiver.sol Line: 33
IRouterClient private s_router;
-
Found in src/Receiver.sol Line: 34
IERC20 private s_linkToken;
-
Found in src/Relayer.sol Line: 19
IRouterClient private s_router;
-
Found in src/Relayer.sol Line: 20
LinkTokenInterface private s_linkToken;
-
Found in src/Sender.sol Line: 18
IRouterClient private s_router;
-
Found in src/Sender.sol Line: 19
LinkTokenInterface private s_linkToken;
-
Found in src/Subscription.sol Line: 31
address private s_sepoliaCheckBalanceAddress;
-
Found in src/Subscription.sol Line: 32
uint64[] private s_subscriptionChainsSelector;
-
Found in src/Subscription.sol Line: 33
address private s_allowedToken;
-
Found in src/Subscription.sol Line: 34
address private s_allowedTokenForOptionalChain;
-
Found in src/Subscription.sol Line: 35
IRouterClient private s_router;
-
Found in src/Subscription.sol Line: 38
Sender private s_sender;