This is the top-ranked automated findings report, from warden ChasetheLights's LightChaser bot. All findings in this report will be considered known issues for the purposes of your C4 audit.
Number | Details | Instances |
---|---|---|
[HIGH-1] | Contract contains payable multicall | 2 |
Number | Details | Instances |
---|---|---|
[MEDIUM-1] | Privileged functions can create points of failure | 25 |
[MEDIUM-2] | Contracts are vulnerable to fee-on-transfer accounting-related issues | 4 |
[MEDIUM-3] | Gas grief possible on unsafe external calls | 15 |
[MEDIUM-5] | If statement with missing revert keyword | 1763 |
[MEDIUM-6] | NFT minting can allow JSON Injection | 19 |
[MEDIUM-7] | Remaining eth may not be refunded to users | 4 |
Number | Details | Instances |
---|---|---|
[LOW-1] | Low level calls in solidity versions preceding 0.8.14 can result in an optimiser bug | 36 |
[LOW-2] | Empty receive functions can cause gas issues | 5 |
[LOW-3] | The call abi.encodeWithSelector is not type safe | 12 |
[LOW-4] | Upgradable contracts should have a __gap variable | 2 |
[LOW-6] | Double type casts create complexity within the code | 3 |
[LOW-7] | Use SafeCast to safely downcast variables | 6 |
[LOW-8] | Upgradable contracts should have an initialization function | 2 |
[LOW-9] | Functions which set address state variables should have zero address checks | 15 |
[LOW-10] | Max allowance is not compatible with all tokens | 2 |
[LOW-11] | Function calls within for loops | 11 |
[LOW-12] | For loops in public or external functions should be avoided due to high gas costs and possible DOS | 7 |
[LOW-14] | Minting to the zero address should be avoided | 4 |
[LOW-15] | Contracts do not use their OZ upgradable counterparts | 1 |
[LOW-16] | Contract inherits Pausable but does not expose pausing/unpausing functionality | 2 |
[LOW-17] | Loss of precision | 4 |
[LOW-18] | Missing zero address check in constructor | 18 |
[LOW-19] | Use of onlyOwner functions can be lost | 1 |
[LOW-20] | Using zero as a parameter | 6 |
[LOW-21] | Solidity version 0.8.20 won't work on all chains due to PUSH0 | 73 |
[LOW-22] | increase/decrease allowance should be used instead of approve | 3 |
[LOW-23] | Contract existence is not checked before low level call | 2 |
[LOW-24] | Storage Write Removal Bug On Conditional Early Termination | 2 |
[LOW-25] | Functions calling contracts/addresses with transfer hooks are missing reentrancy guards | 2 |
[LOW-26] | Revert on Transfer to the Zero Address | 5 |
[LOW-27] | Two or more functions contain the exact same code | 27 |
[LOW-28] | Constructors contains no validation | 7 |
[LOW-29] | Utilizing delegatecall within a loop | 1 |
[LOW-30] | Must approve or increase allowance first | 7 |
Number | Details | Instances |
---|---|---|
[NC-1] | Floating pragma should be avoided | 73 |
[NC-2] | Empty function blocks | 7 |
[NC-3] | In functions which accept an address as a parameter, there should be a zero address check to prevent bugs | 74 |
[NC-4] | Default int values are manually set | 2 |
[NC-5] | Default address values are manually set | 1 |
[NC-6] | Keccak state variables should be immutable not constant | 23 |
[NC-7] | Zero address checks should be present in constructors which take address(es) as parameters | 23 |
[NC-8] | Ownable2Step should be used in place of Ownable | 1 |
[NC-9] | Functions which are either private or internal should have a preceding _ in their name | 7 |
[NC-10] | Private and internal state variables should have a preceding _ in their name unless they are constants | 9 |
[NC-11] | Contract lines should not be longer than 110 characters for readability | 113 |
[NC-12] | Use newer solidity versions | 145 |
[NC-13] | Explicitly define visibility of state variables to prevent misconceptions on what can access the variable | 1 |
[NC-14] | Function names should differ to make the code more readable | 48 |
[NC-15] | Functions should not be longer than 50 lines | 1 |
[NC-16] | It is standard for all external and public functions to be override from an interface | 67 |
[NC-17] | Functions within contracts are not ordered according to the solidity style guide | 11 |
[NC-18] | Emits without msg.sender parameter | 13 |
[NC-19] | Functions with array parameters should have length checks in place | 3 |
[NC-20] | Interface imports should be declared first | 76 |
[NC-21] | Upgradable contract contractors should have the initialize modifier | 2 |
[NC-22] | A function which defines named returns in it's declaration doesn't need to use return | 4 |
[NC-23] | Constant state variables defined more than once | 8 |
[NC-24] | Multiple mappings can be replaced with a single struct mapping | 6 |
[NC-25] | Using abi.encodePacked can result in hash collision when used in hashing functions | 21 |
[NC-26] | Constants should be on the left side of the | 11 |
[NC-27] | Defined named returns not used within function | 30 |
[NC-28] | Both immutable and constant state variables should be CONSTANT_CASE | 19 |
[NC-29] | Consider using named mappings | 6 |
[NC-30] | Use a single file for system wide constants | 40 |
[NC-31] | Functions with unused parameters | 13 |
[NC-32] | Default address(0) can be returned | 30 |
[NC-33] | Critical functions should be a two step procedure | 33 |
[NC-34] | Variables should be used in place of magic numbers to improve readability | 2 |
[NC-35] | Utility contracts can be made into libraries | 6 |
[NC-36] | Address values should be used through variables rather than used as literals | 4 |
[NC-37] | Use immutable not constant for keccak state variables | 21 |
[NC-38] | Unused errors present | 1 |
[NC-39] | Consider adding emergency-stop functionality | 35 |
[NC-40] | Employ Explicit Casting to Bytes or Bytes32 for Enhanced Code Clarity and Meaning | 18 |
[NC-41] | Custom error has no error details | 4 |
[NC-42] | Strings should use double quotes rather than single quotes | 138 |
[NC-43] | Large or complicated code bases should implement invariant tests | 1 |
[NC-44] | Some if-statement can be converted to a ternary | 1 |
[NC-45] | File is missing NatSpec | 20 |
[NC-46] | Addresses shouldn't be hard-coded | 5 |
[NC-47] | Empty bytes check is missing | 99 |
[NC-48] | Consider adding a time delay to upgrade implementation functions | 2 |
Number | Details | Instances | Gas |
---|---|---|---|
[GAS-1] | The use of a logical AND in place of double if is slightly less gas efficient in instances where there isn't a corresponding else statement for the given if statement | 5 | 75 |
[GAS-2] | Calling .length in a for loop wastes gas | 3 | 291 |
[GAS-3] | ++X costs slightly less gas than X++ (same with --) | 3 | 15 |
[GAS-4] | Internal functions never used once can be removed | 4 | - |
[GAS-5] | Internal functions only used once can be inlined so save gas | 31 | 930 |
[GAS-6] | Public functions not used internally can be marked as external to save gas | 15 | - |
[GAS-7] | Solidity version 0.8.19 is more gas efficient | 73 | 73000 |
[GAS-8] | bytes.concat() can be used in place of abi.encodePacked | 3 | - |
[GAS-9] | Constructors can be marked as payable to save deployment gas | 27 | - |
[GAS-10] | Usage of smaller uint/int types causes overhead | 14 | 770 |
[GAS-11] | Avoid updating storage when the value hasn't changed | 32 | 25600 |
[GAS-12] | Use != 0 instead of > 0 | 8 | 24 |
[GAS-13] | Integer increments by one can be unchecked to save on gas fees | 14 | 1680 |
[GAS-14] | Default bool values are manually reset | 8 | - |
[GAS-15] | <= or >= is more efficient than < or > | 1 | 3 |
[GAS-16] | State variables used within a function more than once should be cached to save gas | 34 | 3400 |
[GAS-17] | Mappings used within a function more than once should be cached to save gas | 3 | 300 |
[GAS-18] | Use assembly to check for the zero address | 18 | - |
[GAS-19] | Use storage instead of memory for structs/arrays | 7 | 29400 |
[GAS-20] | Divisions which do not divide by -X cannot overflow or overflow so such operations can be unchecked to save gas | 6 | - |
[GAS-21] | State variables which are not modified within functions should be set as constants or immutable for values set at deployment | 3 | - |
[GAS-22] | Use assembly to calculate hashes to save gas | 42 | 3360 |
[GAS-23] | Redundant else statement | 1 | - |
[GAS-24] | Unbounded Gas Consumption Risk Due to External Call Recipients | 4 | - |
[GAS-25] | Consider activating via-ir for deploying | 73 | 18250 |
[GAS-26] | The result of a function call should be cached rather than re-calling the function | 9 | 900 |
[GAS-27] | Private functions used once can be inlined | 1 | - |
[GAS-28] | Use bitmap to save gas | 10 | 700 |
[GAS-29] | Use assembly hashing | 38 | - |
[GAS-30] | Consider merging sequential for loops | 2 | - |
2
Incorporating multiple delegate calls or ordinary calls in a single payable function can pose significant security risks, especially concerning the potential drainage of funds. Each call in a function can potentially make use of msg.value
(the amount of Ether sent with the function call), and if there's no explicit control over the division of msg.value
across these calls, a user could intentionally or inadvertently trigger a condition where funds are drained from the contract in unexpected ways.
To mitigate these risks, it's crucial to implement rigorous checks and explicit control mechanisms over how msg.value
is used. This may involve ensuring that msg.value
is divided as intended across multiple calls or including checks to prevent recursive or reentrant calls. Additionally, using a 'pull over push' payment design can also provide added security, wherein instead of the contract sending out payments, recipients request withdrawals. This method can limit the amount of Ether that leaves the contract during a single function call and provide better control over funds.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L22-L25
22: function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) {
23: results = new bytes[](data.length);
24: for (uint256 i = 0; i < data.length; ++i) { // <= FOUND
25: (bool success, bytes memory result) = address(this).delegatecall(data[i]); // <= FOUND
26:
27: if (!success) {
28: revert(string(result));
29: }
30:
31: results[i] = result;
32: }
33: }
25
Ensure such accounts are protected and consider implementing multi sig to prevent a single point of failure
Findings are labeled with ' <= FOUND'
Click to show findings
92: function setWhitelistedProposalCaller(
93: string calldata sourceChain,
94: address sourceCaller,
95: bool whitelisted
96: ) external override onlyOwner // <= FOUND
107: function setWhitelistedProposalSender(
108: string calldata sourceChain,
109: address sourceSender,
110: bool whitelisted
111: ) external override onlyOwner // <= FOUND
52: function upgrade(
53: address newImplementation,
54: bytes32 newImplementationCodeHash,
55: bytes calldata params
56: ) external override onlyOwner // <= FOUND
547: function setPaused(bool paused) external onlyOwner // <= FOUND
83: function addTrustedAddress(string memory chain, string memory addr) public onlyOwner // <= FOUND
95: function removeTrustedAddress(string calldata chain) external onlyOwner // <= FOUND
106: function addGatewaySupportedChains(string[] calldata chainNames) external onlyOwner // <= FOUND
119: function removeGatewaySupportedChains(string[] calldata chainNames) external onlyOwner // <= FOUND
161: function getTokenManagerAddress(bytes32 tokenId) public view returns (address tokenManagerAddress) // <= FOUND
170: function getValidTokenManagerAddress(bytes32 tokenId) public view returns (address tokenManagerAddress) // <= FOUND
343: function deployCustomTokenManager( // <= FOUND
344: bytes32 salt,
345: TokenManagerType tokenManagerType, // <= FOUND
346: bytes memory params
347: ) public payable notPaused returns (bytes32 tokenId)
365: function deployRemoteCustomTokenManager( // <= FOUND
366: bytes32 salt,
367: string calldata destinationChain,
368: TokenManagerType tokenManagerType, // <= FOUND
369: bytes calldata params,
370: uint256 gasValue
371: ) external payable notPaused returns (bytes32 tokenId)
502: function transmitSendToken(
503: bytes32 tokenId,
504: address sourceAddress,
505: string calldata destinationChain,
506: bytes memory destinationAddress,
507: uint256 amount,
508: bytes calldata metadata
509: ) external payable onlyTokenManager(tokenId) notPaused // <= FOUND
559: function _sanitizeTokenManagerImplementation(address[] memory implementaions, TokenManagerType tokenManagerType) // <= FOUND
560: internal
561: pure
562: returns (address implementation)
563:
666: function _processDeployTokenManagerPayload(bytes calldata payload) internal // <= FOUND
678: function _processDeployStandardizedTokenAndManagerPayload(bytes calldata payload) internal // <= FOUND
748: function _deployRemoteTokenManager( // <= FOUND
749: bytes32 tokenId,
750: string calldata destinationChain,
751: uint256 gasValue,
752: TokenManagerType tokenManagerType, // <= FOUND
753: bytes memory params
754: ) internal
808: function _deployTokenManager( // <= FOUND
809: bytes32 tokenId,
810: TokenManagerType tokenManagerType, // <= FOUND
811: bytes memory params
812: ) internal
40: function getTokenManager() public view override returns (ITokenManager) // <= FOUND
8: function tokenManagerRequiresApproval() public pure override returns (bool) // <= FOUND
33: function deployTokenManager( // <= FOUND
34: bytes32 tokenId,
35: uint256 implementationType,
36: bytes calldata params
37: ) external payable
4
The below-listed functions use transferFrom()
to move funds from the sender to the recipient but fail to verify if the received token amount matches the transferred amount. This could pose an issue with fee-on-transfer tokens, where the post-transfer balance might be less than anticipated, leading to balance inconsistencies. There might be subsequent checks for a second transfer, but an attacker might exploit leftover funds (such as those accidentally sent by another user) to gain unjustified credit. A practical solution is to gauge the balance prior and post-transfer, and consider the differential as the transferred amount, instead of the predefined amount.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L542-L546
529: function _burnTokenFrom(
530: address sender,
531: string memory symbol,
532: uint256 amount
533: ) internal {
534: address tokenAddress = tokenAddresses(symbol);
535:
536: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
537: if (amount == 0) revert InvalidAmount();
538:
539: TokenType tokenType = _getTokenType(symbol);
540:
541: if (tokenType == TokenType.External) {
542: IERC20(tokenAddress).safeTransferFrom(sender, address(this), amount); // <= FOUND
543: } else if (tokenType == TokenType.InternalBurnableFrom) {
544: IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IBurnableMintableCappedERC20.burnFrom.selector, sender, amount));
545: } else {
546: IERC20(tokenAddress).safeTransferFrom(sender, IBurnableMintableCappedERC20(tokenAddress).depositAddress(bytes32(0)), amount); // <= FOUND
547: IBurnableMintableCappedERC20(tokenAddress).burn(bytes32(0));
548: }
549: }
439: function expressReceiveToken(
440: bytes32 tokenId,
441: address destinationAddress,
442: uint256 amount,
443: bytes32 commandId
444: ) external {
445: if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId);
446:
447: address caller = msg.sender;
448: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
449: IERC20 token = IERC20(tokenManager.tokenAddress());
450:
451: SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount); // <= FOUND
452:
453: _setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, caller);
454: }
467: function expressReceiveTokenWithData(
468: bytes32 tokenId,
469: string memory sourceChain,
470: bytes memory sourceAddress,
471: address destinationAddress,
472: uint256 amount,
473: bytes calldata data,
474: bytes32 commandId
475: ) external {
476: if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId);
477:
478: address caller = msg.sender;
479: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
480: IERC20 token = IERC20(tokenManager.tokenAddress());
481:
482: SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount); // <= FOUND
483:
484: _expressExecuteWithInterchainTokenToken(tokenId, destinationAddress, sourceChain, sourceAddress, data, amount);
485:
486: _setExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, caller);
487: }
15
In Solidity, the use of low-level call
methods can expose contracts to gas griefing attacks. The potential problem arises when the callee contract returns a large amount of data. This data is allocated in the memory of the calling contract, which pays for the gas costs. If the callee contract intentionally returns an enormous amount of data, the gas costs can skyrocket, causing the transaction to fail due to an Out of Gas error. Therefore, it's advisable to limit the use of call
when interacting with untrusted contracts, or ensure that the callee's returned data size is capped or known in advance to prevent unexpected high gas costs.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L322-L373
322: function execute(bytes calldata input) external override { // <= FOUND
323: (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));
324:
325: bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data));
326:
327:
328: bool allowOperatorshipTransfer = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);
329:
330: uint256 chainId;
331: bytes32[] memory commandIds;
332: string[] memory commands;
333: bytes[] memory params;
334:
335: (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));
336:
337: if (chainId != block.chainid) revert InvalidChainId();
338:
339: uint256 commandsLength = commandIds.length;
340:
341: if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
342:
343: for (uint256 i; i < commandsLength; ++i) {
344: bytes32 commandId = commandIds[i];
345:
346: if (isCommandExecuted(commandId)) continue;
347:
348: bytes4 commandSelector;
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));
350:
351: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
352: commandSelector = AxelarGateway.deployToken.selector;
353: } else if (commandHash == SELECTOR_MINT_TOKEN) {
354: commandSelector = AxelarGateway.mintToken.selector;
355: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
356: commandSelector = AxelarGateway.approveContractCall.selector;
357: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
358: commandSelector = AxelarGateway.approveContractCallWithMint.selector;
359: } else if (commandHash == SELECTOR_BURN_TOKEN) {
360: commandSelector = AxelarGateway.burnToken.selector;
361: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
362: if (!allowOperatorshipTransfer) continue;
363:
364: allowOperatorshipTransfer = false;
365: commandSelector = AxelarGateway.transferOperatorship.selector;
366: } else {
367: continue;
368: }
369:
370:
371: _setCommandExecuted(commandId, true);
372:
373: (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId)); // <= FOUND
374:
375: if (success) emit Executed(commandId);
376: else _setCommandExecuted(commandId, false);
377: }
378: }
42: function deployAndInit(
43: bytes memory bytecode,
44: bytes32 salt,
45: bytes calldata init
46: ) external returns (address deployedAddress_) {
47: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt)));
48:
49:
50: (bool success, ) = deployedAddress_.call(init); // <= FOUND
51: if (!success) revert FailedInit();
52: }
49: function deployAndInit(
50: bytes memory bytecode,
51: bytes32 salt,
52: bytes calldata init
53: ) external returns (address deployedAddress_) {
54: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt));
55: deployedAddress_ = Create3.deploy(deploySalt, bytecode);
56:
57: (bool success, ) = deployedAddress_.call(init); // <= FOUND
58: if (!success) revert FailedInit();
59:
60: emit Deployed(keccak256(bytecode), salt, deployedAddress_);
61: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L853-L853
```javascript
841: function _deployStandardizedToken(
842: bytes32 tokenId,
843: address distributor,
844: string memory name,
845: string memory symbol,
846: uint8 decimals,
847: uint256 mintAmount,
848: address mintTo
849: ) internal {
850: bytes32 salt = _getStandardizedTokenSalt(tokenId);
851: address tokenManagerAddress = getTokenManagerAddress(tokenId);
852:
853: (bool success, ) = standardizedTokenDeployer.delegatecall( // <= FOUND
854: abi.encodeWithSelector(
855: IStandardizedTokenDeployer.deployStandardizedToken.selector,
856: salt,
857: tokenManagerAddress,
858: distributor,
859: name,
860: symbol,
861: decimals,
862: mintAmount,
863: mintTo
864: )
865: );
866: if (!success) {
867: revert StandardizedTokenDeploymentFailed();
868: }
869: emit StandardizedTokenDeployed(tokenId, name, symbol, decimals, mintAmount, mintTo);
870: }
19
Reason: JSON injection in NFT metadata can create various vulnerabilities and manipulation tactics in the NFT ecosystem. The metadata of NFTs, often stored off-chain and referenced by URI, could be manipulated through JSON injection if unsanitized inputs are allowed. This could alter the visual representation of an NFT on platforms and mislead buyers or impact the perceived value of the asset.
Resolution: To protect against JSON injection, the metadata processing system should properly sanitize and validate all inputs. Smart contracts should not handle this task due to their limitations. Instead, robust off-chain server code should manage the processing, using tools designed to prevent JSON injection such as input validation, escaping special characters, and utilizing secure JSON parsing libraries. In addition, implementing strict access control to the metadata storage can further safeguard against unauthorized changes.
Findings are labeled with ' <= FOUND'
Click to show findings
841: function _deployStandardizedToken(
842: bytes32 tokenId,
843: address distributor,
844: string memory name, // <= FOUND
845: string memory symbol, // <= FOUND
846: uint8 decimals,
847: uint256 mintAmount, // <= FOUND
848: address mintTo // <= FOUND
849: ) internal {
850: bytes32 salt = _getStandardizedTokenSalt(tokenId);
851: address tokenManagerAddress = getTokenManagerAddress(tokenId);
852:
853: (bool success, ) = standardizedTokenDeployer.delegatecall(
854: abi.encodeWithSelector(
855: IStandardizedTokenDeployer.deployStandardizedToken.selector,
856: salt,
857: tokenManagerAddress,
858: distributor,
859: name, // <= FOUND
860: symbol, // <= FOUND
861: decimals,
862: mintAmount, // <= FOUND
863: mintTo // <= FOUND
864: )
865: );
866: if (!success) {
867: revert StandardizedTokenDeploymentFailed();
868: }
869: emit StandardizedTokenDeployed(tokenId, name, symbol, decimals, mintAmount, mintTo);
870: }
388: function deployAndRegisterStandardizedToken(
389: bytes32 salt,
390: string calldata name, // <= FOUND
391: string calldata symbol, // <= FOUND
392: uint8 decimals,
393: uint256 mintAmount, // <= FOUND
394: address distributor
395: ) external payable notPaused {
396: bytes32 tokenId = getCustomTokenId(msg.sender, salt);
397: _deployStandardizedToken(tokenId, distributor, name, symbol, decimals, mintAmount, msg.sender); // <= FOUND
398: address tokenManagerAddress = getTokenManagerAddress(tokenId);
399: TokenManagerType tokenManagerType = distributor == tokenManagerAddress ? TokenManagerType.MINT_BURN : TokenManagerType.LOCK_UNLOCK;
400: address tokenAddress = getStandardizedTokenAddress(tokenId);
401: _deployTokenManager(tokenId, tokenManagerType, abi.encode(msg.sender.toBytes(), tokenAddress));
402: }
49: function deployStandardizedToken(
50: bytes32 salt,
51: address tokenManager,
52: address distributor,
53: string calldata name, // <= FOUND
54: string calldata symbol, // <= FOUND
55: uint8 decimals,
56: uint256 mintAmount, // <= FOUND
57: address mintTo // <= FOUND
58: ) external payable {
59: bytes memory bytecode;
60: address implementationAddress = distributor == tokenManager ? implementationMintBurnAddress : implementationLockUnlockAddress;
61: {
62: bytes memory params = abi.encode(tokenManager, distributor, name, symbol, decimals, mintAmount, mintTo); // <= FOUND
63: bytecode = abi.encodePacked(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params));
64: }
65: address tokenAddress = deployer.deploy(bytecode, salt);
66: if (tokenAddress.code.length == 0) revert TokenDeploymentFailed();
67: }
4
When a contract function accepts Ethereum and executes a .call()
or similar function that also forwards Ethereum value, it's important to check for and refund any remaining balance. This is because some of the supplied value may not be used during the call execution due to gas constraints, a revert in the called contract, or simply because not all the value was needed.
If you do not account for this remaining balance, it can become "locked" in the contract. It's crucial to either return the remaining balance to the sender or handle it in a way that ensures it is not permanently stuck. Neglecting to do so can lead to loss of funds and degradation of the contract's reliability. Furthermore, it's good practice to ensure fairness and trust with your users by returning unused funds.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Caller.sol#L11-L18
11: function _call(
12: address target,
13: bytes calldata callData,
14: uint256 nativeValue
15: ) internal {
16: if (nativeValue > address(this).balance) revert InsufficientBalance();
17:
18: (bool success, ) = target.call{ value: nativeValue }(callData); // <= FOUND
19: if (!success) {
20: revert ExecutionFailed();
21: }
22: }
73: function _executeProposal(InterchainCalls.Call[] memory calls) internal {
74: for (uint256 i = 0; i < calls.length; i++) {
75: InterchainCalls.Call memory call = calls[i];
76: (bool success, bytes memory result) = call.target.call{ value: call.value }(call.callData); // <= FOUND
77:
78: if (!success) {
79: _onTargetExecutionFailed(call, result);
80: } else {
81: _onTargetExecuted(call, result);
82: }
83: }
84: }
36
In Solidity versions 0.8.13 and 0.8.14, a known optimizer bug presents potential risks when a variable is used in a separate assembly block from the one in which it was stored. Specifically, the 'mstore' operation could be optimized out due to this bug, leading to the use of uninitialized memory. Although the current code does not exhibit this risky pattern of execution, it does utilize 'mstore' within assembly blocks, which introduces a vulnerability risk for future code modifications. As a preventative measure, it is advisable to avoid the usage of the afflicted Solidity versions, 0.8.13 and 0.8.14. Instead, consider utilizing a version that is not impacted by this optimizer bug to prevent potential memory initialization issues in your smart contract.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L95-L95
95: assembly { // <= FOUND
96: eta := sload(key)
97: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L106-L106
106: assembly { // <= FOUND
107: sstore(key, eta)
108: }
84: assembly { // <= FOUND
85: deployedAddress_ := create2(0, add(bytecode, 32), mload(bytecode), salt)
86: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L24-L24
24: assembly { // <= FOUND
25: deployed := create(0, add(bytecode, 32), mload(bytecode))
26: if iszero(deployed) {
27: revert(0, 0)
28: }
29: }
40: assembly { // <= FOUND
41: implementation_ := sload(_IMPLEMENTATION_SLOT)
42: }
40: assembly { // <= FOUND
41: calldatacopy(0, 0, calldatasize())
42:
43: let result := delegatecall(gas(), implementation_, 0, calldatasize(), 0, 0)
44: returndatacopy(0, 0, returndatasize())
45:
46: switch result
47: case 0 {
48: revert(0, returndatasize())
49: }
50: default {
51: return(0, returndatasize())
52: }
53: }
35: assembly { // <= FOUND
36: sstore(_IMPLEMENTATION_SLOT, implementationAddress)
37: sstore(_OWNER_SLOT, owner)
38: }
68: assembly { // <= FOUND
69: sstore(_IMPLEMENTATION_SLOT, newImplementation)
70: }
21: assembly { // <= FOUND
22: sstore(_OWNER_SLOT, caller())
23: }
74: assembly { // <= FOUND
75: owner := sload(_OWNER_SLOT)
76: }
52: assembly { // <= FOUND
53: sstore(_IMPLEMENTATION_SLOT, implementationAddress)
54: sstore(_OWNER_SLOT, newOwner)
55: }
603: assembly { // <= FOUND
604: commandId := calldataload(4)
605: }
873: assembly { // <= FOUND
874: data.length := sub(metadata.length, 4)
875: data.offset := add(metadata.offset, 4)
876: version := calldataload(sub(metadata.offset, 28))
877: }
20: assembly { // <= FOUND
21: addr := mload(add(bytesAddress, 20))
22: }
33: assembly { // <= FOUND
34: mstore(add(bytesAddress, 20), addr)
35: mstore(bytesAddress, 20)
36: }
75: assembly { // <= FOUND
76: calldatacopy(0, 0, calldatasize())
77:
78: let result := delegatecall(gas(), implementaion_, 0, calldatasize(), 0, 0)
79: returndatacopy(0, 0, returndatasize())
80:
81: switch result
82: case 0 {
83: revert(0, returndatasize())
84: }
85: default {
86: return(0, returndatasize())
87: }
88: }
29: assembly { // <= FOUND
30: tokenAddress_ := sload(TOKEN_ADDRESS_SLOT)
31: }
39: assembly { // <= FOUND
40: sstore(TOKEN_ADDRESS_SLOT, tokenAddress_)
41: }
48: assembly { // <= FOUND
49: sstore(LIQUIDITY_POOL_SLOT, liquidityPool_)
50: }
58: assembly { // <= FOUND
59: liquidityPool_ := sload(LIQUIDITY_POOL_SLOT)
60: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L30-L30
30: assembly { // <= FOUND
31: distr := sload(DISTRIBUTOR_SLOT)
32: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L40-L40
40: assembly { // <= FOUND
41: sstore(DISTRIBUTOR_SLOT, distributor_)
42: }
88: assembly { // <= FOUND
89: prevExpressCaller := sload(slot)
90: }
92: assembly { // <= FOUND
93: sstore(slot, expressCaller)
94: }
155: assembly { // <= FOUND
156: expressCaller := sload(slot)
157: }
213: assembly { // <= FOUND
214: sstore(slot, 0)
215: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L25-L25
25: assembly { // <= FOUND
26: flowLimit := sload(FLOW_LIMIT_SLOT)
27: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L35-L35
35: assembly { // <= FOUND
36: sstore(FLOW_LIMIT_SLOT, flowLimit)
37: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L66-L66
66: assembly { // <= FOUND
67: flowOutAmount := sload(slot)
68: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L78-L78
78: assembly { // <= FOUND
79: flowInAmount := sload(slot)
80: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L97-L97
97: assembly { // <= FOUND
98: flowToAdd := sload(slotToAdd)
99: flowToCompare := sload(slotToCompare)
100: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L102-L102
102: assembly { // <= FOUND
103: sstore(slotToAdd, add(flowToAdd, flowAmount))
104: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L30-L30
30: assembly { // <= FOUND
31: operator_ := sload(OPERATOR_SLOT)
32: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L40-L40
40: assembly { // <= FOUND
41: sstore(OPERATOR_SLOT, operator_)
42: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L30-L30
30: assembly { // <= FOUND
31: paused := sload(PAUSE_SLOT)
32: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L42-L42
42: assembly { // <= FOUND
43: sstore(PAUSE_SLOT, paused)
44: }
5
In Solidity, functions that receive Ether without corresponding functionality to utilize or withdraw these funds can inadvertently lead to a permanent loss of value. This is because if someone sends Ether to the contract, they may be unable to retrieve it. To avoid this, functions receiving Ether should be accompanied by additional methods that process or allow the withdrawal of these funds. If the intent is to use the received Ether, it should trigger a separate function; if not, it should revert the transaction (for instance, via require(msg.sender == address(weth))
). Access control checks can also prevent unintended Ether transfers, despite the slight gas cost they entail. If concerns over gas costs persist, at minimum, include a rescue function to recover unused Ether. Missteps in handling Ether in smart contracts can lead to irreversible financial losses, hence these precautions are crucial.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L41-L41
41: receive() external payable {}
59: receive() external payable virtual {}
12
The call abi.encodeCall shout be used instead. Note abi.encodeCall is only safe from typographical errors in solidity versions 0.8.13 and above
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L293-L293
279: function upgrade(
280: address newImplementation,
281: bytes32 newImplementationCodeHash,
282: bytes calldata setupParams
283: ) external override onlyGovernance {
284: if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();
285:
286: if (AxelarGateway(newImplementation).contractId() != contractId()) revert InvalidImplementation();
287:
288: emit Upgraded(newImplementation);
289:
290:
291:
292: if (setupParams.length != 0) {
293: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(IAxelarGateway.setup.selector, setupParams)); // <= FOUND
294:
295: if (!success) revert SetupFailed();
296: }
297:
298: _setImplementation(newImplementation);
299: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L373-L373
322: function execute(bytes calldata input) external override {
323: (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));
324:
325: bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data));
326:
327:
328: bool allowOperatorshipTransfer = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);
329:
330: uint256 chainId;
331: bytes32[] memory commandIds;
332: string[] memory commands;
333: bytes[] memory params;
334:
335: (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));
336:
337: if (chainId != block.chainid) revert InvalidChainId();
338:
339: uint256 commandsLength = commandIds.length;
340:
341: if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
342:
343: for (uint256 i; i < commandsLength; ++i) {
344: bytes32 commandId = commandIds[i];
345:
346: if (isCommandExecuted(commandId)) continue;
347:
348: bytes4 commandSelector;
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));
350:
351: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
352: commandSelector = AxelarGateway.deployToken.selector;
353: } else if (commandHash == SELECTOR_MINT_TOKEN) {
354: commandSelector = AxelarGateway.mintToken.selector;
355: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
356: commandSelector = AxelarGateway.approveContractCall.selector;
357: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
358: commandSelector = AxelarGateway.approveContractCallWithMint.selector;
359: } else if (commandHash == SELECTOR_BURN_TOKEN) {
360: commandSelector = AxelarGateway.burnToken.selector;
361: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
362: if (!allowOperatorshipTransfer) continue;
363:
364: allowOperatorshipTransfer = false;
365: commandSelector = AxelarGateway.transferOperatorship.selector;
366: } else {
367: continue;
368: }
369:
370:
371: _setCommandExecuted(commandId, true);
372:
373: (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId)); // <= FOUND
374:
375: if (success) emit Executed(commandId);
376: else _setCommandExecuted(commandId, false);
377: }
378: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L398-L398
384: function deployToken(bytes calldata params, bytes32) external onlySelf {
385: (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode(
386: params,
387: (string, string, uint8, uint256, address, uint256)
388: );
389:
390:
391: if (tokenAddresses(symbol) != address(0)) revert TokenAlreadyExists(symbol);
392:
393: if (tokenAddress == address(0)) {
394:
395: bytes32 salt = keccak256(abi.encodePacked(symbol));
396:
397: (bool success, bytes memory data) = TOKEN_DEPLOYER_IMPLEMENTATION.delegatecall(
398: abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt) // <= FOUND
399: );
400:
401: if (!success) revert TokenDeployFailed(symbol);
402:
403: tokenAddress = abi.decode(data, (address));
404:
405: _setTokenType(symbol, TokenType.InternalBurnableFrom);
406: } else {
407:
408: if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);
409:
410:
411: _setTokenType(symbol, TokenType.External);
412: }
413:
414: _setTokenAddress(symbol, tokenAddress);
415: _setTokenMintLimit(symbol, mintLimit);
416:
417: emit TokenDeployed(symbol, tokenAddress);
418: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L442-L442
426: function burnToken(bytes calldata params, bytes32) external onlySelf {
427: (string memory symbol, bytes32 salt) = abi.decode(params, (string, bytes32));
428:
429: address tokenAddress = tokenAddresses(symbol);
430:
431: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
432:
433: if (_getTokenType(symbol) == TokenType.External) {
434: address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode)));
435:
436: if (_hasCode(depositHandlerAddress)) return;
437:
438: DepositHandler depositHandler = new DepositHandler{ salt: salt }();
439:
440: (bool success, bytes memory returnData) = depositHandler.execute(
441: tokenAddress,
442: abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler))) // <= FOUND
443: );
444:
445: if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol);
446:
447:
448: depositHandler.destroy(address(this));
449: } else {
450: IBurnableMintableCappedERC20(tokenAddress).burn(salt);
451: }
452: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L544-L544
529: function _burnTokenFrom(
530: address sender,
531: string memory symbol,
532: uint256 amount
533: ) internal {
534: address tokenAddress = tokenAddresses(symbol);
535:
536: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
537: if (amount == 0) revert InvalidAmount();
538:
539: TokenType tokenType = _getTokenType(symbol);
540:
541: if (tokenType == TokenType.External) {
542: IERC20(tokenAddress).safeTransferFrom(sender, address(this), amount);
543: } else if (tokenType == TokenType.InternalBurnableFrom) {
544: IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IBurnableMintableCappedERC20.burnFrom.selector, sender, amount)); // <= FOUND
545: } else {
546: IERC20(tokenAddress).safeTransferFrom(sender, IBurnableMintableCappedERC20(tokenAddress).depositAddress(bytes32(0)), amount);
547: IBurnableMintableCappedERC20(tokenAddress).burn(bytes32(0));
548: }
549: }
52: function upgrade(
53: address newImplementation,
54: bytes32 newImplementationCodeHash,
55: bytes calldata params
56: ) external override onlyOwner {
57: if (IUpgradable(newImplementation).contractId() != IUpgradable(this).contractId()) revert InvalidImplementation();
58: if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();
59:
60: if (params.length > 0) {
61: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params)); // <= FOUND
62:
63: if (!success) revert SetupFailed();
64: }
65:
66: emit Upgraded(newImplementation);
67:
68: assembly {
69: sstore(_IMPLEMENTATION_SLOT, newImplementation)
70: }
71: }
35: function init(
36: address implementationAddress,
37: address newOwner,
38: bytes memory params
39: ) external {
40: address owner;
41:
42: assembly {
43: owner := sload(_OWNER_SLOT)
44: }
45:
46: if (msg.sender != owner) revert NotOwner();
47: if (implementation() != address(0)) revert AlreadyInitialized();
48:
49: bytes32 id = contractId();
50: if (id != bytes32(0) && IUpgradable(implementationAddress).contractId() != id) revert InvalidImplementation();
51:
52: assembly {
53: sstore(_IMPLEMENTATION_SLOT, implementationAddress)
54: sstore(_OWNER_SLOT, newOwner)
55: }
56:
57: if (params.length != 0) {
58: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IUpgradable.setup.selector, params)); // <= FOUND
59: if (!success) revert SetupFailed();
60: }
61: }
72: function finalUpgrade(bytes memory bytecode, bytes calldata setupParams) public returns (address finalImplementation_) {
73: address owner;
74: assembly {
75: owner := sload(_OWNER_SLOT)
76: }
77: if (msg.sender != owner) revert NotOwner();
78:
79: finalImplementation_ = Create3.deploy(FINAL_IMPLEMENTATION_SALT, bytecode);
80: if (setupParams.length != 0) {
81: (bool success, ) = finalImplementation_.delegatecall(abi.encodeWithSelector(BaseProxy.setup.selector, setupParams)); // <= FOUND
82: if (!success) revert SetupFailed();
83: }
84: }
808: function _deployTokenManager(
809: bytes32 tokenId,
810: TokenManagerType tokenManagerType,
811: bytes memory params
812: ) internal {
813: (bool success, ) = tokenManagerDeployer.delegatecall(
814: abi.encodeWithSelector(ITokenManagerDeployer.deployTokenManager.selector, tokenId, tokenManagerType, params) // <= FOUND
815: );
816: if (!success) {
817: revert TokenManagerDeploymentFailed();
818: }
819: emit TokenManagerDeployed(tokenId, tokenManagerType, params);
820: }
841: function _deployStandardizedToken(
842: bytes32 tokenId,
843: address distributor,
844: string memory name,
845: string memory symbol,
846: uint8 decimals,
847: uint256 mintAmount,
848: address mintTo
849: ) internal {
850: bytes32 salt = _getStandardizedTokenSalt(tokenId);
851: address tokenManagerAddress = getTokenManagerAddress(tokenId);
852:
853: (bool success, ) = standardizedTokenDeployer.delegatecall(
854: abi.encodeWithSelector( // <= FOUND
855: IStandardizedTokenDeployer.deployStandardizedToken.selector,
856: salt,
857: tokenManagerAddress,
858: distributor,
859: name,
860: symbol,
861: decimals,
862: mintAmount,
863: mintTo
864: )
865: );
866: if (!success) {
867: revert StandardizedTokenDeploymentFailed();
868: }
869: emit StandardizedTokenDeployed(tokenId, name, symbol, decimals, mintAmount, mintTo);
870: }
45: function _takeToken(address from, uint256 amount) internal override returns (uint256) {
46: IERC20 token = IERC20(tokenAddress());
47:
48: SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20BurnableMintable.burn.selector, from, amount)); // <= FOUND
49:
50: return amount;
51: }
59: function _giveToken(address to, uint256 amount) internal override returns (uint256) {
60: IERC20 token = IERC20(tokenAddress());
61:
62: SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20BurnableMintable.mint.selector, to, amount)); // <= FOUND
63:
64: return amount;
65: }
2
This is to ensure the team can add new state variables without compromising compatability.
Findings are labeled with ' <= FOUND'
Click to show findings
37: contract InterchainTokenService is
38: IInterchainTokenService,
39: AxelarExecutable,
40: Upgradable,
41: Operatable,
42: ExpressCallHandler,
43: Pausable,
44: Multicall
45:
12: contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable
3
Double type casting should be avoided in Solidity contracts to prevent unintended consequences and ensure accurate data representation. Performing multiple type casts in succession can lead to unexpected truncation, rounding errors, or loss of precision, potentially compromising the contract's functionality and reliability. Furthermore, double type casting can make the code less readable and harder to maintain, increasing the likelihood of errors and misunderstandings during development and debugging. To ensure precise and consistent data handling, developers should use appropriate data types and avoid unnecessary or excessive type casting, promoting a more robust and dependable contract execution.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L615-L615
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash))))); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L72-L72
72: address deployer = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', sender, salt, DEPLOYER_BYTECODE_HASH))))); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L74-L74
74: deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01'))))); // <= FOUND
6
Downcasting int/uints in Solidity can be unsafe due to the potential for data loss and unintended behavior. When downcasting a larger integer type to a smaller one (e.g., uint256 to uint128), the value may exceed the range of the target type, leading to truncation and loss of significant digits. This data loss can result in unexpected state changes, incorrect calculations, or other contract vulnerabilities, ultimately compromising the contracts functionality and reliability. To prevent these risks, developers should carefully consider the range of values their variables may hold and ensure that proper checks are in place to prevent out-of-range values before performing downcasting. Also consider using OZ SafeCast functionality.
Findings are labeled with ' <= FOUND'
Click to show findings
54: function _lowerCase(string memory s) internal pure returns (string memory) {
55: uint256 length = bytes(s).length;
56: for (uint256 i; i < length; i++) {
57: uint8 b = uint8(bytes(s)[i]); // <= FOUND
58: if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32)); // <= FOUND
59: }
60: return s;
61: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L615-L615
614: function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) {
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash))))); // <= FOUND
616: }
58: function deployedAddress(
59: bytes calldata bytecode,
60: address sender,
61: bytes32 salt
62: ) external view returns (address deployedAddress_) {
63: bytes32 newSalt = keccak256(abi.encode(sender, salt));
64: deployedAddress_ = address(
65: uint160( // <= FOUND
66: uint256(
67: keccak256(
68: abi.encodePacked(
69: hex'ff',
70: address(this),
71: newSalt,
72: keccak256(bytecode)
73: )
74: )
75: )
76: )
77: );
78: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L72-L74
71: function deployedAddress(address sender, bytes32 salt) internal pure returns (address deployed) {
72: address deployer = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', sender, salt, DEPLOYER_BYTECODE_HASH))))); // <= FOUND
73:
74: deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01'))))); // <= FOUND
75: }
2
Upgradable contracts in Solidity should have an initialization function to ensure proper setup, maintain state consistency, and enhance security. Unlike regular contracts, upgradable contracts use a proxy pattern that separates the contract's logic from its data storage, enabling seamless updates to the logic without affecting the stored data. However, this approach requires careful initialization of the contract state to avoid inconsistencies or vulnerabilities.
Findings are labeled with ' <= FOUND'
Click to show findings
37: contract InterchainTokenService is
38: IInterchainTokenService,
39: AxelarExecutable,
40: Upgradable, // <= FOUND
41: Operatable,
42: ExpressCallHandler,
43: Pausable,
44: Multicall
45: {
46: using StringToBytes32 for string;
47: using Bytes32ToString for bytes32;
48: using AddressBytesUtils for bytes;
49: using AddressBytesUtils for address;
50:
51: address internal immutable implementationLockUnlock;
52: address internal immutable implementationMintBurn;
53: address internal immutable implementationLiquidityPool;
54: IAxelarGasService public immutable gasService;
55: IRemoteAddressValidator public immutable remoteAddressValidator;
56: address public immutable tokenManagerDeployer;
57: address public immutable standardizedTokenDeployer;
58: Create3Deployer internal immutable deployer;
59: bytes32 internal immutable chainNameHash;
60: bytes32 internal immutable chainName;
61:
62: bytes32 internal constant PREFIX_CUSTOM_TOKEN_ID = keccak256('its-custom-token-id');
63: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_ID = keccak256('its-standardized-token-id');
64: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_SALT = keccak256('its-standardized-token-salt');
12: contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { // <= FOUND
13: using AddressToString for address;
14:
15: mapping(string => bytes32) public remoteAddressHashes;
16: mapping(string => string) public remoteAddresses;
17: address public immutable interchainTokenServiceAddress;
18: bytes32 public immutable interchainTokenServiceAddressHash;
19: mapping(string => bool) public supportedByGateway;
20:
21: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator');
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
15
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L643-L643
643: function _setTokenAddress(string memory symbol, address tokenAddress) internal {
644: _setAddress(_getTokenAddressKey(symbol), tokenAddress);
645: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L651-L651
651: function _setContractCallApproved(
652: bytes32 commandId,
653: string memory sourceChain,
654: string memory sourceAddress,
655: address contractAddress,
656: bytes32 payloadHash
657: ) internal {
658: _setBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash), true);
659: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L661-L661
661: function _setContractCallApprovedWithMint(
662: bytes32 commandId,
663: string memory sourceChain,
664: string memory sourceAddress,
665: address contractAddress,
666: bytes32 payloadHash,
667: string memory symbol,
668: uint256 amount
669: ) internal {
670: _setBool(
671: _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount),
672: true
673: );
674: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L676-L676
676: function _setImplementation(address newImplementation) internal {
677: _setAddress(KEY_IMPLEMENTATION, newImplementation);
678: }
38: function _setTokenAddress(address tokenAddress_) internal {
39: assembly {
40: sstore(TOKEN_ADDRESS_SLOT, tokenAddress_)
41: }
42: }
47: function _setLiquidityPool(address liquidityPool_) internal {
48: assembly {
49: sstore(LIQUIDITY_POOL_SLOT, liquidityPool_)
50: }
51: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L39-L39
39: function _setDistributor(address distributor_) internal {
40: assembly {
41: sstore(DISTRIBUTOR_SLOT, distributor_)
42: }
43: emit DistributorChanged(distributor_);
44: }
79: function _setExpressReceiveToken(
80: bytes32 tokenId,
81: address destinationAddress,
82: uint256 amount,
83: bytes32 commandId,
84: address expressCaller
85: ) internal {
86: uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId);
87: address prevExpressCaller;
88: assembly {
89: prevExpressCaller := sload(slot)
90: }
91: if (prevExpressCaller != address(0)) revert AlreadyExpressCalled();
92: assembly {
93: sstore(slot, expressCaller)
94: }
95: emit ExpressReceive(tokenId, destinationAddress, amount, commandId, expressCaller);
96: }
110: function _setExpressReceiveTokenWithData(
111: bytes32 tokenId,
112: string memory sourceChain,
113: bytes memory sourceAddress,
114: address destinationAddress,
115: uint256 amount,
116: bytes calldata data,
117: bytes32 commandId,
118: address expressCaller
119: ) internal {
120: uint256 slot = _getExpressReceiveTokenWithDataSlot(
121: tokenId,
122: sourceChain,
123: sourceAddress,
124: destinationAddress,
125: amount,
126: data,
127: commandId
128: );
129: address prevExpressCaller;
130: assembly {
131: prevExpressCaller := sload(slot)
132: }
133: if (prevExpressCaller != address(0)) revert AlreadyExpressCalled();
134: assembly {
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L39-L39
39: function _setOperator(address operator_) internal {
40: assembly {
41: sstore(OPERATOR_SLOT, operator_)
42: }
43: emit OperatorChanged(operator_);
44: }
92: function setWhitelistedProposalCaller(
93: string calldata sourceChain,
94: address sourceCaller,
95: bool whitelisted
96: ) external override onlyOwner {
97: whitelistedCallers[sourceChain][sourceCaller] = whitelisted;
98: emit WhitelistedProposalCallerSet(sourceChain, sourceCaller, whitelisted);
99: }
107: function setWhitelistedProposalSender(
108: string calldata sourceChain,
109: address sourceSender,
110: bool whitelisted
111: ) external override onlyOwner {
112: whitelistedSenders[sourceChain][sourceSender] = whitelisted;
113: emit WhitelistedProposalSenderSet(sourceChain, sourceSender, whitelisted);
114: }
67: function setLiquidityPool(address newLiquidityPool) external onlyOperator {
68: _setLiquidityPool(newLiquidityPool);
69: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L51-L51
51: function setDistributor(address distr) external onlyDistributor {
52: _setDistributor(distr);
53: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L51-L51
51: function setOperator(address operator_) external onlyOperator {
52: _setOperator(operator_);
53: }
2
Findings are labeled with ' <= FOUND'
Click to show findings
43: function interchainTransfer(
44: string calldata destinationChain,
45: bytes calldata recipient,
46: uint256 amount,
47: bytes calldata metadata
48: ) external payable {
49: address sender = msg.sender;
50: ITokenManager tokenManager = getTokenManager();
51:
52:
53:
54: if (tokenManagerRequiresApproval()) {
55: uint256 allowance_ = allowance[sender][address(tokenManager)];
56: if (allowance_ != type(uint256).max) {
57: if (allowance_ > type(uint256).max - amount) {
58: allowance_ = type(uint256).max - amount; // <= FOUND
59: }
60:
61: _approve(sender, address(tokenManager), allowance_ + amount);
62: }
63: }
64:
65:
66: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata);
67: }
79: function interchainTransferFrom(
80: address sender,
81: string calldata destinationChain,
82: bytes calldata recipient,
83: uint256 amount,
84: bytes calldata metadata
85: ) external payable {
86: uint256 _allowance = allowance[sender][msg.sender];
87:
88: if (_allowance != type(uint256).max) {
89: _approve(sender, msg.sender, _allowance - amount);
90: }
91:
92: ITokenManager tokenManager = getTokenManager();
93: if (tokenManagerRequiresApproval()) {
94: uint256 allowance_ = allowance[sender][address(tokenManager)];
95: if (allowance_ != type(uint256).max) {
96: if (allowance_ > type(uint256).max - amount) {
97: allowance_ = type(uint256).max - amount; // <= FOUND
98: }
99:
100: _approve(sender, address(tokenManager), allowance_ + amount);
101: }
102: }
103:
104: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata);
105: }
11
Making function calls or external calls within loops in Solidity can lead to inefficient gas usage, potential bottlenecks, and increased vulnerability to attacks. Each function call or external call consumes gas, and when executed within a loop, the gas cost multiplies, potentially causing the transaction to run out of gas or exceed block gas limits. This can result in transaction failure or unpredictable behavior.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L273-L275
269: for (uint256 i; i < length; ++i) {
270: string memory symbol = symbols[i];
271: uint256 limit = limits[i];
272:
273: if (tokenAddresses(symbol) == address(0)) revert TokenDoesNotExist(symbol); // <= FOUND
274:
275: _setTokenMintLimit(symbol, limit); // <= FOUND
276: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L346-L376
343: for (uint256 i; i < commandsLength; ++i) {
344: bytes32 commandId = commandIds[i];
345:
346: if (isCommandExecuted(commandId)) continue; // <= FOUND
347:
348: bytes4 commandSelector;
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));
350:
351: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
352: commandSelector = AxelarGateway.deployToken.selector;
353: } else if (commandHash == SELECTOR_MINT_TOKEN) {
354: commandSelector = AxelarGateway.mintToken.selector;
355: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
356: commandSelector = AxelarGateway.approveContractCall.selector;
357: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
358: commandSelector = AxelarGateway.approveContractCallWithMint.selector;
359: } else if (commandHash == SELECTOR_BURN_TOKEN) {
360: commandSelector = AxelarGateway.burnToken.selector;
361: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
362: if (!allowOperatorshipTransfer) continue;
363:
364: allowOperatorshipTransfer = false;
365: commandSelector = AxelarGateway.transferOperatorship.selector;
366: } else {
367: continue;
368: }
369:
370:
371: _setCommandExecuted(commandId, true); // <= FOUND
372:
373: (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId));
374:
375: if (success) emit Executed(commandId);
376: else _setCommandExecuted(commandId, false); // <= FOUND
377: }
63: for (uint256 i = 0; i < interchainCalls.length; ) {
64: _sendProposal(interchainCalls[i]); // <= FOUND
65: unchecked {
66: ++i;
67: }
68: }
74: for (uint256 i = 0; i < calls.length; i++) {
75: InterchainCalls.Call memory call = calls[i];
76: (bool success, bytes memory result) = call.target.call{ value: call.value }(call.callData);
77:
78: if (!success) {
79: _onTargetExecutionFailed(call, result); // <= FOUND
80: } else {
81: _onTargetExecuted(call, result); // <= FOUND
82: }
83: }
537: for (uint256 i; i < length; ++i) {
538: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenIds[i])); // <= FOUND
539: tokenManager.setFlowLimit(flowLimits[i]); // <= FOUND
540: }
44: for (uint256 i; i < length; ++i) {
45: addTrustedAddress(trustedChainNames[i], trustedAddresses[i]); // <= FOUND
46: }
[LOW-12] For loops in public or external functions should be avoided due to high gas costs and possible DOS
7
In Solidity, for loops can potentially cause Denial of Service (DoS) attacks if not handled carefully. DoS attacks can occur when an attacker intentionally exploits the gas cost of a function, causing it to run out of gas or making it too expensive for other users to call. Below are some scenarios where for loops can lead to DoS attacks: Nested for loops can become exceptionally gas expensive and should be used sparingly
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L122-L122
119: function getSignerVotesCount(bytes32 topic) external view override returns (uint256) {
120: uint256 length = signers.accounts.length;
121: uint256 voteCount;
122: for (uint256 i; i < length; ++i) { // <= FOUND
123: if (votingPerTopic[signerEpoch][topic].hasVoted[signers.accounts[i]]) {
124: voteCount++;
125: }
126: }
127:
128: return voteCount;
129: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L269-L269
265: function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external override onlyMintLimiter {
266: uint256 length = symbols.length;
267: if (length != limits.length) revert InvalidSetMintLimitsParams();
268:
269: for (uint256 i; i < length; ++i) { // <= FOUND
270: string memory symbol = symbols[i];
271: uint256 limit = limits[i];
272:
273: if (tokenAddresses(symbol) == address(0)) revert TokenDoesNotExist(symbol);
274:
275: _setTokenMintLimit(symbol, limit);
276: }
277: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L343-L343
322: function execute(bytes calldata input) external override {
323: (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));
324:
325: bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data));
326:
327:
328: bool allowOperatorshipTransfer = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);
329:
330: uint256 chainId;
331: bytes32[] memory commandIds;
332: string[] memory commands;
333: bytes[] memory params;
334:
335: (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));
336:
337: if (chainId != block.chainid) revert InvalidChainId();
338:
339: uint256 commandsLength = commandIds.length;
340:
341: if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
342:
343: for (uint256 i; i < commandsLength; ++i) { // <= FOUND
344: bytes32 commandId = commandIds[i];
345:
346: if (isCommandExecuted(commandId)) continue;
347:
348: bytes4 commandSelector;
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));
350:
351: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
352: commandSelector = AxelarGateway.deployToken.selector;
353: } else if (commandHash == SELECTOR_MINT_TOKEN) {
354: commandSelector = AxelarGateway.mintToken.selector;
355: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
356: commandSelector = AxelarGateway.approveContractCall.selector;
357: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
358: commandSelector = AxelarGateway.approveContractCallWithMint.selector;
359: } else if (commandHash == SELECTOR_BURN_TOKEN) {
360: commandSelector = AxelarGateway.burnToken.selector;
361: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
362: if (!allowOperatorshipTransfer) continue;
363:
364: allowOperatorshipTransfer = false;
365: commandSelector = AxelarGateway.transferOperatorship.selector;
366: } else {
367: continue;
59: function sendProposals(InterchainCalls.InterchainCall[] calldata interchainCalls) external payable override {
60:
61: revertIfInvalidFee(interchainCalls);
62:
63: for (uint256 i = 0; i < interchainCalls.length; ) { // <= FOUND
64: _sendProposal(interchainCalls[i]);
65: unchecked {
66: ++i;
67: }
68: }
69: }
534: function setFlowLimit(bytes32[] calldata tokenIds, uint256[] calldata flowLimits) external onlyOperator {
535: uint256 length = tokenIds.length;
536: if (length != flowLimits.length) revert LengthMismatch();
537: for (uint256 i; i < length; ++i) { // <= FOUND
538: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenIds[i]));
539: tokenManager.setFlowLimit(flowLimits[i]);
540: }
541: }
106: function addGatewaySupportedChains(string[] calldata chainNames) external onlyOwner {
107: uint256 length = chainNames.length;
108: for (uint256 i; i < length; ++i) { // <= FOUND
109: string calldata chainName = chainNames[i];
110: supportedByGateway[chainName] = true;
111: emit GatewaySupportedChainAdded(chainName);
112: }
113: }
119: function removeGatewaySupportedChains(string[] calldata chainNames) external onlyOwner {
120: uint256 length = chainNames.length;
121: for (uint256 i; i < length; ++i) { // <= FOUND
122: string calldata chainName = chainNames[i];
123: supportedByGateway[chainName] = false;
124: emit GatewaySupportedChainRemoved(chainName);
125: }
126: }
4
Minting tokens to the zero address in Solidity is a potential pitfall that should be carefully guarded against. The zero address (0x0) is generally used as a default value and represents an uninitialized or null address. Minting tokens to this address effectively burns them, making them inaccessible and permanently removing them from the total supply. This could lead to unintended token loss if performed accidentally. To prevent this, it's important to include a check in the minting function to ensure that the target address is not the zero address. Using a library like OpenZeppelin's Address
can provide utility functions like requireNonZero
, which simplifies this check and enhances the security of the minting function.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L511-L511
511: function _mintToken(
512: string memory symbol,
513: address account,
514: uint256 amount
515: ) internal
388: function deployAndRegisterStandardizedToken(
389: bytes32 salt,
390: string calldata name,
391: string calldata symbol,
392: uint8 decimals,
393: uint256 mintAmount,
394: address distributor
395: ) external payable notPaused
841: function _deployStandardizedToken(
842: bytes32 tokenId,
843: address distributor,
844: string memory name,
845: string memory symbol,
846: uint8 decimals,
847: uint256 mintAmount,
848: address mintTo
849: ) internal
49: function deployStandardizedToken(
50: bytes32 salt,
51: address tokenManager,
52: address distributor,
53: string calldata name,
54: string calldata symbol,
55: uint8 decimals,
56: uint256 mintAmount,
57: address mintTo
58: ) external payable
1
Using the upgradeable counterpart of the OpenZeppelin (OZ) library in Solidity is beneficial for creating contracts that can be updated in the future. OpenZeppelin's upgradeable contracts library is designed with proxy patterns in mind, which allow the logic of contracts to be upgraded while preserving the contract's state and address. This can be crucial for long-lived contracts where future requirements or improvements may not be fully known at the time of deployment. The upgradeable OZ contracts also include protection against a class of vulnerabilities related to initialization of storage variables in upgradeable contracts. Hence, it's a good idea to use them when developing contracts that may need to be upgraded in the future, as they provide a solid foundation for secure and upgradeable smart contracts.
Findings are labeled with ' <= FOUND'
Click to show findings
37: contract InterchainTokenService is
38: IInterchainTokenService,
39: AxelarExecutable,
40: Upgradable,
41: Operatable,
42: ExpressCallHandler,
43: Pausable, // <= FOUND
44: Multicall
45:
2
When a contract inherits from the Pausable contract in Solidity, it gains the ability to pause and resume certain actions, which can be crucial in mitigating potential risks or issues. However, the _pause and _unpause functions are internal and can only be called from within the contract or derived contracts. If the functionality to pause and unpause isn't exposed through public or external functions, it can't be called by the contract owner or designated pauser account.
Resolution: To take advantage of the Pausable contract, create public or external functions that call _pause and _unpause.
Findings are labeled with ' <= FOUND'
Click to show findings
37: contract InterchainTokenService is
38: IInterchainTokenService,
39: AxelarExecutable,
40: Upgradable,
41: Operatable,
42: ExpressCallHandler,
43: Pausable,
44: Multicall
45:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L12-L12
12: contract Pausable is IPausable
4
Dividing by large numbers in Solidity can cause a loss of precision due to the language's inherent integer division behavior. Solidity does not support floating-point arithmetic, and as a result, division between integers yields an integer result, truncating any fractional part. When dividing by a large number, the resulting value may become significantly smaller, leading to a loss of precision, as the fractional part is discarded.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L64-L64
63: function getFlowOutAmount() external view returns (uint256 flowOutAmount) {
64: uint256 epoch = block.timestamp / EPOCH_TIME; // <= FOUND
65: uint256 slot = _getFlowOutSlot(epoch);
66: assembly {
67: flowOutAmount := sload(slot)
68: }
69: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L76-L76
75: function getFlowInAmount() external view returns (uint256 flowInAmount) {
76: uint256 epoch = block.timestamp / EPOCH_TIME; // <= FOUND
77: uint256 slot = _getFlowInSlot(epoch);
78: assembly {
79: flowInAmount := sload(slot)
80: }
81: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L114-L114
111: function _addFlowOut(uint256 flowOutAmount) internal {
112: uint256 flowLimit = getFlowLimit();
113: if (flowLimit == 0) return;
114: uint256 epoch = block.timestamp / EPOCH_TIME; // <= FOUND
115: uint256 slotToAdd = _getFlowOutSlot(epoch);
116: uint256 slotToCompare = _getFlowInSlot(epoch);
117: _addFlow(flowLimit, slotToAdd, slotToCompare, flowOutAmount);
118: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L127-L127
124: function _addFlowIn(uint256 flowInAmount) internal {
125: uint256 flowLimit = getFlowLimit();
126: if (flowLimit == 0) return;
127: uint256 epoch = block.timestamp / EPOCH_TIME; // <= FOUND
128: uint256 slotToAdd = _getFlowInSlot(epoch);
129: uint256 slotToCompare = _getFlowOutSlot(epoch);
130: _addFlow(flowLimit, slotToAdd, slotToCompare, flowInAmount);
131: }
18
In Solidity, constructors often take address parameters to initialize important components of a contract, such as owner or linked contracts. However, without a check, there's a risk that an address parameter could be mistakenly set to the zero address (0x0). This could occur due to a mistake or oversight during contract deployment. A zero address in a crucial role can cause serious issues, as it cannot perform actions like a normal address, and any funds sent to it are irretrievable. Therefore, it's crucial to include a zero address check in constructors to prevent such potential problems. If a zero address is detected, the constructor should revert the transaction.
Findings are labeled with ' <= FOUND'
Click to show findings
33: constructor(
34: address gateway, // <= FOUND
35: string memory governanceChain_,
36: string memory governanceAddress_,
37: uint256 minimumTimeDelay
38: ) AxelarExecutable(gateway) TimeLock(minimumTimeDelay) {
39: governanceChain = governanceChain_;
40: governanceAddress = governanceAddress_;
41: governanceChainHash = keccak256(bytes(governanceChain_));
42: governanceAddressHash = keccak256(bytes(governanceAddress_));
43: }
33: constructor(
34: address gateway, // <= FOUND
35: string memory governanceChain,
36: string memory governanceAddress,
37: uint256 minimumTimeDelay,
38: address[] memory cosigners,
39: uint256 threshold
40: ) InterchainGovernance(gateway, governanceChain, governanceAddress, minimumTimeDelay) MultisigBase(cosigners, threshold) {}
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L64-L64
64: constructor(address authModule_, address tokenDeployerImplementation_) { // <= FOUND
65: if (authModule_.code.length == 0) revert InvalidAuthModule();
66: if (tokenDeployerImplementation_.code.length == 0) revert InvalidTokenDeployer();
67:
68: AUTH_MODULE = authModule_;
69: TOKEN_DEPLOYER_IMPLEMENTATION = tokenDeployerImplementation_;
70: }
42: constructor(address _gateway, address _gasService) { // <= FOUND
43: gateway = IAxelarGateway(_gateway);
44: gasService = IAxelarGasService(_gasService);
45: }
29: constructor(address _gateway, address _owner) AxelarExecutable(_gateway) { // <= FOUND
30: _transferOwnership(_owner);
31: }
26: constructor(
27: address implementationAddress, // <= FOUND
28: address owner, // <= FOUND
29: bytes memory setupParams
30: ) Proxy(implementationAddress, owner, setupParams) {}
23: constructor(address implementationAddress) { // <= FOUND
24: implementation = implementationAddress;
25: }
19: constructor(
20: address implementationAddress, // <= FOUND
21: address owner, // <= FOUND
22: address operator // <= FOUND
23: ) FinalProxy(implementationAddress, owner, abi.encodePacked(operator)) {}
20: constructor(
21: address implementationAddress, // <= FOUND
22: address owner, // <= FOUND
23: bytes memory params
24: ) Proxy(implementationAddress, owner, params) {}
21: constructor(address implementationAddress, bytes memory params) FixedProxy(implementationAddress) { // <= FOUND
22: if (IStandardizedToken(implementationAddress).contractId() != CONTRACT_ID) revert InvalidImplementation();
23:
24: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IStandardizedToken.setup.selector, params));
25: if (!success) revert SetupFailed();
26: }
25: constructor(
26: address interchainTokenServiceAddress_, // <= FOUND
27: uint256 implementationType_,
28: bytes32 tokenId_,
29: bytes memory params
30: ) {
31: interchainTokenServiceAddress = IInterchainTokenService(interchainTokenServiceAddress_);
32: implementationType = implementationType_;
33: tokenId = tokenId_;
34: address impl = _getImplementation(IInterchainTokenService(interchainTokenServiceAddress_), implementationType_); // <= FOUND
35:
36: (bool success, ) = impl.delegatecall(abi.encodeWithSelector(TokenManagerProxy.setup.selector, params));
37: if (!success) revert SetupFailed();
38: }
19: constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {} // <= FOUND
22: constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} // <= FOUND
1
In Solidity, renouncing ownership of a contract essentially transfers ownership to the zero address. This is an irreversible operation and has considerable security implications. If the renounceOwnership function is used, the contract will lose the ability to perform any operations that are limited to the owner. This can be problematic if there are any bugs, flaws, or unexpected events that require owner intervention to resolve. Therefore, in some instances, it is better to disable or omit the renounceOwnership function, and instead implement a secure transferOwnership function. This way, if necessary, ownership can be transferred to a new, trusted party without losing the potential for administrative intervention.
Findings are labeled with ' <= FOUND'
Click to show findings
22: contract InterchainProposalExecutor is IInterchainProposalExecutor, AxelarExecutable, Ownable // <= FOUND
6
Taking 0 as a valid argument in Solidity without checks can lead to severe security issues. A historical example is the infamous 0x0 address bug where numerous tokens were lost. This happens because '0' can be interpreted as an uninitialized address, leading to transfers to the '0x0' address, effectively burning tokens. Moreover, 0 as a denominator in division operations would cause a runtime exception. It's also often indicative of a logical error in the caller's code. It's important to always validate input and handle edge cases like 0 appropriately. Use require()
statements to enforce conditions and provide clear error messages to facilitate debugging and safer code.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L67-L70
67: function _cancelTimeLock(bytes32 hash) internal { // <= FOUND
68: if (hash == 0) revert InvalidTimeLockHash();
69:
70: _setTimeLockEta(hash, 0); // <= FOUND
71: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L79-L86
79: function _finalizeTimeLock(bytes32 hash) internal { // <= FOUND
80: uint256 eta = _getTimeLockEta(hash);
81:
82: if (hash == 0 || eta == 0) revert InvalidTimeLockHash();
83:
84: if (block.timestamp < eta) revert TimeLockNotReady();
85:
86: _setTimeLockEta(hash, 0); // <= FOUND
87: }
678: function _processDeployStandardizedTokenAndManagerPayload(bytes calldata payload) internal { // <= FOUND
679: (
680: ,
681: bytes32 tokenId,
682: string memory name,
683: string memory symbol,
684: uint8 decimals,
685: bytes memory distributorBytes,
686: bytes memory operatorBytes
687: ) = abi.decode(payload, (uint256, bytes32, string, string, uint8, bytes, bytes));
688: address tokenAddress = getStandardizedTokenAddress(tokenId);
689: address tokenManagerAddress = getTokenManagerAddress(tokenId);
690: address distributor = distributorBytes.length > 0 ? distributorBytes.toAddress() : tokenManagerAddress;
691: _deployStandardizedToken(tokenId, distributor, name, symbol, decimals, 0, distributor); // <= FOUND
692: TokenManagerType tokenManagerType = distributor == tokenManagerAddress ? TokenManagerType.MINT_BURN : TokenManagerType.LOCK_UNLOCK;
693: _deployTokenManager(
694: tokenId,
695: tokenManagerType,
696: abi.encode(operatorBytes.length == 0 ? address(this).toBytes() : operatorBytes, tokenAddress)
697: );
698: }
73
Solidity version 0.8.20 uses the new Shanghai EVM which introduces the PUSH0 opcode, this may not be implemented on all chains and L2 thus reducing the portability and compatability of the code. Consider using a earlier solidity version.
Findings are labeled with ' <= FOUND'
Click to show findings
3: pragma solidity ^0.8.0; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L3-L3
3: pragma solidity ^0.8.9; // <= FOUND
3
In order to prevent front running, increase/decrease allowance should be used in place of approve where possible
Findings are labeled with ' <= FOUND'
Click to show findings
43: function interchainTransfer(
44: string calldata destinationChain,
45: bytes calldata recipient,
46: uint256 amount,
47: bytes calldata metadata
48: ) external payable {
49: address sender = msg.sender;
50: ITokenManager tokenManager = getTokenManager();
51:
52:
53:
54: if (tokenManagerRequiresApproval()) {
55: uint256 allowance_ = allowance[sender][address(tokenManager)];
56: if (allowance_ != type(uint256).max) {
57: if (allowance_ > type(uint256).max - amount) {
58: allowance_ = type(uint256).max - amount;
59: }
60:
61: _approve(sender, address(tokenManager), allowance_ + amount); // <= FOUND
62: }
63: }
64:
65:
66: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata);
67: }
79: function interchainTransferFrom(
80: address sender,
81: string calldata destinationChain,
82: bytes calldata recipient,
83: uint256 amount,
84: bytes calldata metadata
85: ) external payable {
86: uint256 _allowance = allowance[sender][msg.sender];
87:
88: if (_allowance != type(uint256).max) {
89: _approve(sender, msg.sender, _allowance - amount); // <= FOUND
90: }
91:
92: ITokenManager tokenManager = getTokenManager();
93: if (tokenManagerRequiresApproval()) {
94: uint256 allowance_ = allowance[sender][address(tokenManager)];
95: if (allowance_ != type(uint256).max) {
96: if (allowance_ > type(uint256).max - amount) {
97: allowance_ = type(uint256).max - amount;
98: }
99:
100: _approve(sender, address(tokenManager), allowance_ + amount); // <= FOUND
101: }
102: }
103:
104: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata);
105: }
2
Low-level assembly calls, such as call, can return a successful status even when the target address contains no executable code. This is due to the fact that a call operation merely checks if the call operation itself was successful, not whether the call was made to an address with code. As a result, these calls might lead to false positives when assessing the success of an operation. To prevent potential issues, consider using Solidity's extcodesize function to check the size of the contract code at the target address. If extcodesize returns zero, this indicates that there is no code at the specified address, and the function can safely revert.
Findings are labeled with ' <= FOUND'
Click to show findings
603: assembly {
604: commandId := calldataload(4) // <= FOUND
605: }
873: assembly {
874: data.length := sub(metadata.length, 4)
875: data.offset := add(metadata.offset, 4)
876: version := calldataload(sub(metadata.offset, 28)) // <= FOUND
877: }
2
In September 2022, a bug in Solidity’s Yul optimizer was identified through differential fuzzing. This bug, introduced in version 0.8.13 and fixed by version 0.8.17, can be activated easier with optimized via-IR code generation but can also potentially occur in optimized legacy code generation. This bug is of medium/high severity, which requires contracts that use large inline assembly blocks containing user-defined assembly functions involving return(...) or stop() instructions to be reviewed.
The bug is associated with the Unused Store Eliminator in Yul optimizer, which removes redundant storage writes, and is triggered when function calls are performed. If the function call conditionally continues after the call to a function and terminates using return(...) or stop(), the optimizer may incorrectly remove storage writes before calls to the function.
To evaluate if a contract is affected, you need to check contracts that include inline assembly block with return(...) or stop() statements. If early termination happens conditionally within a function, the optimizer might remove storage writes before function calls.
To avoid this, contracts should not allow for conditional early termination within a function. It is also recommended to use a version of Solidity where this bug has been fixed (version 0.8.17 or later).
Findings are labeled with ' <= FOUND'
Click to show findings
40: assembly {
41: calldatacopy(0, 0, calldatasize())
42:
43: let result := delegatecall(gas(), implementation_, 0, calldatasize(), 0, 0)
44: returndatacopy(0, 0, returndatasize())
45:
46: switch result
47: case 0 {
48: revert(0, returndatasize())
49: }
50: default {
51: return(0, returndatasize()) // <= FOUND
52: }
53: }
75: assembly {
76: calldatacopy(0, 0, calldatasize())
77:
78: let result := delegatecall(gas(), implementaion_, 0, calldatasize(), 0, 0)
79: returndatacopy(0, 0, returndatasize())
80:
81: switch result
82: case 0 {
83: revert(0, returndatasize())
84: }
85: default {
86: return(0, returndatasize()) // <= FOUND
87: }
88: }
2
While adherence to the check-effects-interaction pattern is commendable, the absence of a reentrancy guard in functions, especially where transfer hooks might be present, can expose the protocol users to risks of read-only reentrancies. Such reentrancy vulnerabilities can be exploited to execute malicious actions even without altering the contract state. Without a reentrancy guard, the only potential mitigation would be to blocklist the entire protocol - an extreme and disruptive measure. Therefore, incorporating a reentrancy guard into these functions is vital to bolster security, as it helps protect against both traditional reentrancy attacks and read-only reentrancies, ensuring robust and safe protocol operations.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L523-L523
511: function _mintToken(
512: string memory symbol,
513: address account,
514: uint256 amount
515: ) internal {
516: address tokenAddress = tokenAddresses(symbol);
517:
518: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
519:
520: _setTokenMintAmount(symbol, tokenMintAmount(symbol) + amount);
521:
522: if (_getTokenType(symbol) == TokenType.External) {
523: IERC20(tokenAddress).safeTransfer(account, amount); // <= FOUND
524: } else {
525: IBurnableMintableCappedERC20(tokenAddress).mint(account, amount);
526: }
527: }
60: function _giveToken(address to, uint256 amount) internal override returns (uint256) {
61: IERC20 token = IERC20(tokenAddress());
62: uint256 balance = IERC20(token).balanceOf(to);
63:
64: SafeTokenTransfer.safeTransfer(token, to, amount); // <= FOUND
65:
66: return IERC20(token).balanceOf(to) - balance;
67: }
5
Many ERC-20 and ERC-721 token contracts implement a safeguard that reverts transactions which attempt to transfer tokens to the zero address. This is because such transfers are often the result of programming errors. The OpenZeppelin library, a popular choice for implementing these standards, includes this safeguard. For token contract developers who want to avoid unintentional transfers to the zero address, it's good practice to include a condition that reverts the transaction if the recipient's address is the zero address.
Findings are labeled with ' <= FOUND'
Click to show findings
439: function expressReceiveToken(
440: bytes32 tokenId,
441: address destinationAddress,
442: uint256 amount,
443: bytes32 commandId
444: ) external {
445: if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId);
446:
447: address caller = msg.sender;
448: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
449: IERC20 token = IERC20(tokenManager.tokenAddress());
450:
451: SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount); // <= FOUND
452:
453: _setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, caller);
454: }
467: function expressReceiveTokenWithData(
468: bytes32 tokenId,
469: string memory sourceChain,
470: bytes memory sourceAddress,
471: address destinationAddress,
472: uint256 amount,
473: bytes calldata data,
474: bytes32 commandId
475: ) external {
476: if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId);
477:
478: address caller = msg.sender;
479: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
480: IERC20 token = IERC20(tokenManager.tokenAddress());
481:
482: SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount); // <= FOUND
483:
484: _expressExecuteWithInterchainTokenToken(tokenId, destinationAddress, sourceChain, sourceAddress, data, amount);
485:
486: _setExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, caller);
487: }
44: function _takeToken(address from, uint256 amount) internal override returns (uint256) {
45: IERC20 token = IERC20(tokenAddress());
46: uint256 balance = token.balanceOf(address(this));
47:
48: SafeTokenTransferFrom.safeTransferFrom(token, from, address(this), amount); // <= FOUND
49:
50:
51: return IERC20(token).balanceOf(address(this)) - balance;
52: }
77: function _takeToken(address from, uint256 amount) internal override returns (uint256) {
78: IERC20 token = IERC20(tokenAddress());
79: address liquidityPool_ = liquidityPool();
80: uint256 balance = token.balanceOf(liquidityPool_);
81:
82: SafeTokenTransferFrom.safeTransferFrom(token, from, liquidityPool_, amount); // <= FOUND
83:
84:
85: return IERC20(token).balanceOf(liquidityPool_) - balance;
86: }
94: function _giveToken(address to, uint256 amount) internal override returns (uint256) {
95: IERC20 token = IERC20(tokenAddress());
96: uint256 balance = IERC20(token).balanceOf(to);
97:
98: SafeTokenTransferFrom.safeTransferFrom(token, liquidityPool(), to, amount); // <= FOUND
99:
100: return IERC20(token).balanceOf(to) - balance;
101: }
27
In Solidity programming, duplicate code in multiple functions introduces potential security risks and maintainability issues. It magnifies the impact of any bugs or vulnerabilities, since developers must fix these in every location where the code is replicated. Overlooking any instance of replicated code could leave vulnerabilities intact. Furthermore, code duplication leads to contract bloating, diminishing the readability and manageability of the code. Future logic changes would need to be applied in every location where the code is replicated, increasing the complexity of updates. To resolve this, it is recommended to consolidate duplicate code into a single internal function, and replace the duplicate instances with calls to this new function. This approach streamlines the code, reducing the attack surface and making it easier to maintain and update.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L208-L208
208: function allTokensFrozen() external pure override returns (bool) { // <= FOUND
209: return false;
210: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L213-L213
213: function adminEpoch() external pure override returns (uint256) { // <= FOUND
214: return 0;
215: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L218-L218
218: function adminThreshold(uint256) external pure override returns (uint256) { // <= FOUND
219: return 0;
220: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L237-L237
237: function tokenFrozen(string memory) external pure override returns (bool) { // <= FOUND
238: return false;
239: }
126: function _beforeProposalExecuted(
127: string calldata sourceChain,
128: string calldata sourceAddress,
129: bytes calldata payload
130: ) internal virtual {
131:
132: }
142: function _onProposalExecuted(
143: string calldata,
144: string calldata,
145: address,
146: bytes calldata payload
147: ) internal virtual {
148:
149: }
178: function _onTargetExecuted(InterchainCalls.Call memory call, bytes memory result) internal virtual { // <= FOUND
179:
180: }
22: function implementation() public view virtual returns (address implementation_) { // <= FOUND
23: assembly {
24: implementation_ := sload(_IMPLEMENTATION_SLOT)
25: }
26: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L306-L306
306: function setup(bytes calldata params) external override { // <= FOUND
307:
308: if (implementation() == address(0)) revert NotProxy();
309:
310: (address governance_, address mintLimiter_, bytes memory newOperatorsData) = abi.decode(params, (address, address, bytes));
311:
312: if (governance_ != address(0)) _transferGovernance(governance_);
313: if (mintLimiter_ != address(0)) _transferMintLimiter(mintLimiter_);
314:
315: if (newOperatorsData.length != 0) {
316: IAxelarAuth(AUTH_MODULE).transferOperatorship(newOperatorsData);
317:
318: emit OperatorshipTransferred(newOperatorsData);
319: }
320: }
32: function setup(bytes calldata params) external {} // <= FOUND
49: function setup(bytes calldata params) external override onlyProxy { // <= FOUND
50: {
51: address distributor_;
52: address tokenManager_;
53: string memory tokenName;
54: (tokenManager_, distributor_, tokenName, symbol, decimals) = abi.decode(params, (address, address, string, string, uint8));
55: _setDistributor(distributor_);
56: tokenManager = tokenManager_;
57: _setDomainTypeSignatureHash(tokenName);
58: name = tokenName;
59: }
60: {
61: uint256 mintAmount;
62: address mintTo;
63: (, , , , , mintAmount, mintTo) = abi.decode(params, (address, address, string, string, uint8, uint256, address));
64: if (mintAmount > 0) {
65: _mint(mintTo, mintAmount);
66: }
67: }
68: }
61: function setup(bytes calldata params) external override onlyProxy { // <= FOUND
62: bytes memory operatorBytes = abi.decode(params, (bytes));
63: address operator_;
64:
65:
66:
67:
68: if (operatorBytes.length == 0) {
69: operator_ = address(interchainTokenService);
70: } else {
71: operator_ = operatorBytes.toAddress();
72: }
73: _setOperator(operator_);
74: _setup(params);
75: }
39: function implementation() public view returns (address implementation_) { // <= FOUND
40: assembly {
41: implementation_ := sload(_IMPLEMENTATION_SLOT)
42: }
43: }
87: function _setup(bytes calldata data) internal virtual {} // <= FOUND
31: function setup(bytes calldata setupParams) external {} // <= FOUND
36: function contractId() external pure returns (bytes32) { // <= FOUND
37: return CONTRACT_ID;
38: }
241: function getParamsLockUnlock(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) { // <= FOUND
242: params = abi.encode(operator, tokenAddress);
243: }
251: function getParamsMintBurn(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) { // <= FOUND
252: params = abi.encode(operator, tokenAddress);
253: }
30: function contractId() internal pure override returns (bytes32) { // <= FOUND
31: return CONTRACT_ID;
32: }
8: function tokenManagerRequiresApproval() public pure override returns (bool) { // <= FOUND
9: return true;
10: }
8: function tokenManagerRequiresApproval() public pure override returns (bool) { // <= FOUND
9: return false;
10: }
136: function transmitInterchainTransfer(
137: address sender,
138: string calldata destinationChain,
139: bytes calldata destinationAddress,
140: uint256 amount,
141: bytes calldata metadata
142: ) external payable virtual onlyToken {
143: amount = _takeToken(sender, amount);
144: _addFlowOut(amount);
145: interchainTokenService.transmitSendToken{ value: msg.value }(
146: _getTokenId(),
147: sender,
148: destinationChain,
149: destinationAddress,
150: amount,
151: metadata
152: );
153: }
24: function implementationType() external pure returns (uint256) { // <= FOUND
25: return 0;
26: }
25: function implementationType() external pure returns (uint256) { // <= FOUND
26: return 1;
27: }
28: function implementationType() external pure returns (uint256) { // <= FOUND
29: return 2;
30: }
555: function _setup(bytes calldata params) internal override { // <= FOUND
556: _setOperator(params.toAddress());
557: }
40: function _setup(bytes calldata params) internal override { // <= FOUND
41: (string[] memory trustedChainNames, string[] memory trustedAddresses) = abi.decode(params, (string[], string[]));
42: uint256 length = trustedChainNames.length;
43: if (length != trustedAddresses.length) revert LengthMismatch();
44: for (uint256 i; i < length; ++i) {
45: addTrustedAddress(trustedChainNames[i], trustedAddresses[i]);
46: }
47: }
32: function _setup(bytes calldata params) internal override { // <= FOUND
33:
34: (, address tokenAddress) = abi.decode(params, (bytes, address));
35: _setTokenAddress(tokenAddress);
36: }
36: function _setup(bytes calldata params) internal override { // <= FOUND
37:
38: (, address tokenAddress_, address liquidityPool_) = abi.decode(params, (bytes, address, address));
39: _setTokenAddress(tokenAddress_);
40: _setLiquidityPool(liquidityPool_);
41: }
148: function getExpressReceiveToken(
149: bytes32 tokenId,
150: address destinationAddress,
151: uint256 amount,
152: bytes32 commandId
153: ) public view returns (address expressCaller) {
154: uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId);
155: assembly {
156: expressCaller := sload(slot)
157: }
158: }
171: function getExpressReceiveTokenWithData(
172: bytes32 tokenId,
173: string memory sourceChain,
174: bytes memory sourceAddress,
175: address destinationAddress,
176: uint256 amount,
177: bytes calldata data,
178: bytes32 commandId
179: ) public view returns (address expressCaller) {
180: uint256 slot = _getExpressReceiveTokenWithDataSlot(
181: tokenId,
182: sourceChain,
183: sourceAddress,
184: destinationAddress,
185: amount,
186: data,
187: commandId
188: );
189: assembly {
190: expressCaller := sload(slot)
191: }
192: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L51-L51
51: function setOperator(address operator_) external onlyOperator { // <= FOUND
52: _setOperator(operator_);
53: }
7
In Solidity, when values are being assigned in constructors to unsigned or integer variables, it's crucial to ensure the provided values adhere to the protocol's specific operational boundaries as laid out in the project specifications and documentation. If the constructors lack appropriate validation checks, there's a risk of setting state variables with values that could cause unexpected and potentially detrimental behavior within the contract's operations, violating the intended logic of the protocol. This can compromise the contract's security and impact the maintainability and reliability of the system. In order to avoid such issues, it is recommended to incorporate rigorous validation checks in constructors. These checks should align with the project's defined rules and constraints, making use of Solidity's built-in require function to enforce these conditions. If the validation checks fail, the require function will cause the transaction to revert, ensuring the integrity and adherence to the protocol's expected behavior.
Findings are labeled with ' <= FOUND'
Click to show findings
33: constructor(
34: address gateway,
35: string memory governanceChain_,
36: string memory governanceAddress_,
37: uint256 minimumTimeDelay // <= FOUND
38: ) AxelarExecutable(gateway) TimeLock(minimumTimeDelay) {
39: governanceChain = governanceChain_; // <= FOUND
40: governanceAddress = governanceAddress_; // <= FOUND
41: governanceChainHash = keccak256(bytes(governanceChain_)); // <= FOUND
42: governanceAddressHash = keccak256(bytes(governanceAddress_)); // <= FOUND
43: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L21-L22
21: constructor(uint256 minimumTimeDelay) { // <= FOUND
22: _minimumTimeLockDelay = minimumTimeDelay; // <= FOUND
23: }
1
Using delegatecall
in a for
loop can lead to high gas costs, as delegatecall
is an expensive operation and its costs compound when used in a loop. Additionally, it can pose security risks including reentrancy attacks, as it executes code in the calling contract's context. The function selector collisions can also lead to unpredictable behaviour. To mitigate these risks, control the loop's iterations, apply a reentrancy guard, strictly audit contracts called via delegatecall
, and consider alternatives like call
or proxy patterns if the use case allows. Always thoroughly vet contracts involved in delegatecall
operations.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L25-L25
24: for (uint256 i = 0; i < data.length; ++i) {
25: (bool success, bytes memory result) = address(this).delegatecall(data[i]); // <= FOUND
26:
27: if (!success) {
28: revert(string(result));
29: }
30:
31: results[i] = result;
32: }
7
In the context of ERC20 tokens, a token holder needs to "approve" another account to transfer a certain amount of their tokens on their behalf. This is accomplished by calling the approve()
function, which takes the address of the spender and the amount they're allowed to spend as parameters.
This approval step is a crucial part of the ERC20 standard because it allows for secure delegated transfers. A common use case for this feature is in decentralized exchanges or DeFi protocols, where a user can approve a smart contract to transfer tokens on their behalf.
After the approval step, the approved account (or contract) can then transfer tokens up to the approved amount from the token holder's account by calling the transferFrom()
function. This function takes three parameters: the address of the token holder, the recipient's address, and the amount to transfer.
If an account tries to call transferFrom()
before the token holder has called approve()
, the transaction will fail because the ERC20 contract checks whether the transferFrom()
caller has an adequate allowance.
In summary, if a contract or user needs to move ERC20 tokens on behalf of another account, it's necessary to ensure that the token holder has first called approve()
to set a sufficient allowance. This is a key aspect of ERC20 token security and functionality.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L529-L546
529: function _burnTokenFrom(
530: address sender,
531: string memory symbol,
532: uint256 amount
533: ) internal {
534: address tokenAddress = tokenAddresses(symbol);
535:
536: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
537: if (amount == 0) revert InvalidAmount();
538:
539: TokenType tokenType = _getTokenType(symbol);
540:
541: if (tokenType == TokenType.External) {
542: IERC20(tokenAddress).safeTransferFrom(sender, address(this), amount); // <= FOUND
543: } else if (tokenType == TokenType.InternalBurnableFrom) {
544: IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IBurnableMintableCappedERC20.burnFrom.selector, sender, amount));
545: } else {
546: IERC20(tokenAddress).safeTransferFrom(sender, IBurnableMintableCappedERC20(tokenAddress).depositAddress(bytes32(0)), amount); // <= FOUND
547: IBurnableMintableCappedERC20(tokenAddress).burn(bytes32(0));
548: }
549: }
439: function expressReceiveToken(
440: bytes32 tokenId,
441: address destinationAddress,
442: uint256 amount,
443: bytes32 commandId
444: ) external {
445: if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId);
446:
447: address caller = msg.sender;
448: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
449: IERC20 token = IERC20(tokenManager.tokenAddress());
450:
451: SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount); // <= FOUND
452:
453: _setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, caller);
454: }
467: function expressReceiveTokenWithData(
468: bytes32 tokenId,
469: string memory sourceChain,
470: bytes memory sourceAddress,
471: address destinationAddress,
472: uint256 amount,
473: bytes calldata data,
474: bytes32 commandId
475: ) external {
476: if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId);
477:
478: address caller = msg.sender;
479: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
480: IERC20 token = IERC20(tokenManager.tokenAddress());
481:
482: SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount); // <= FOUND
483:
484: _expressExecuteWithInterchainTokenToken(tokenId, destinationAddress, sourceChain, sourceAddress, data, amount);
485:
486: _setExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, caller);
487: }
44: function _takeToken(address from, uint256 amount) internal override returns (uint256) {
45: IERC20 token = IERC20(tokenAddress());
46: uint256 balance = token.balanceOf(address(this));
47:
48: SafeTokenTransferFrom.safeTransferFrom(token, from, address(this), amount); // <= FOUND
49:
50:
51: return IERC20(token).balanceOf(address(this)) - balance;
52: }
77: function _takeToken(address from, uint256 amount) internal override returns (uint256) {
78: IERC20 token = IERC20(tokenAddress());
79: address liquidityPool_ = liquidityPool();
80: uint256 balance = token.balanceOf(liquidityPool_);
81:
82: SafeTokenTransferFrom.safeTransferFrom(token, from, liquidityPool_, amount); // <= FOUND
83:
84:
85: return IERC20(token).balanceOf(liquidityPool_) - balance;
86: }
94: function _giveToken(address to, uint256 amount) internal override returns (uint256) {
95: IERC20 token = IERC20(tokenAddress());
96: uint256 balance = IERC20(token).balanceOf(to);
97:
98: SafeTokenTransferFrom.safeTransferFrom(token, liquidityPool(), to, amount); // <= FOUND
99:
100: return IERC20(token).balanceOf(to) - balance;
101: }
73
Findings are labeled with ' <= FOUND'
Click to show findings
3: pragma solidity ^0.8.0; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L3-L3
3: pragma solidity ^0.8.9; // <= FOUND
7
Empty code blocks (i.e., {}) in a Solidity contract can be harmful as they can lead to ambiguity, misinterpretation, and unintended behavior. When developers encounter empty code blocks, it may be unclear whether the absence of code is intentional or the result of an oversight. This uncertainty can cause confusion during development, testing, and debugging, increasing the likelihood of introducing errors or vulnerabilities. Moreover, empty code blocks may give a false impression of implemented functionality or security measures, creating a misleading sense of assurance. To ensure clarity and maintainability, it is essential to avoid empty code blocks and explicitly document the intended behavior or any intentional omissions.
Findings are labeled with ' <= FOUND'
Click to show findings
126: function _beforeProposalExecuted(
127: string calldata sourceChain,
128: string calldata sourceAddress,
129: bytes calldata payload
130: ) internal virtual {
131:
132: }
142: function _onProposalExecuted(
143: string calldata,
144: string calldata,
145: address,
146: bytes calldata payload
147: ) internal virtual {
148:
149: }
178: function _onTargetExecuted(InterchainCalls.Call memory call, bytes memory result) internal virtual {
179:
180: }
32: function setup(bytes calldata params) external {}
87: function _setup(bytes calldata data) internal virtual {}
31: function setup(bytes calldata setupParams) external {}
33: constructor(
34: address gateway,
35: string memory governanceChain,
36: string memory governanceAddress,
37: uint256 minimumTimeDelay,
38: address[] memory cosigners,
39: uint256 threshold
40: ) InterchainGovernance(gateway, governanceChain, governanceAddress, minimumTimeDelay) MultisigBase(cosigners, threshold) {}
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L20-L20
20: constructor(address[] memory accounts, uint256 threshold) MultisigBase(accounts, threshold) {}
26: constructor(
27: address implementationAddress,
28: address owner,
29: bytes memory setupParams
30: ) Proxy(implementationAddress, owner, setupParams) {}
19: constructor(
20: address implementationAddress,
21: address owner,
22: address operator
23: ) FinalProxy(implementationAddress, owner, abi.encodePacked(operator)) {}
20: constructor(
21: address implementationAddress,
22: address owner,
23: bytes memory params
24: ) Proxy(implementationAddress, owner, params) {}
19: constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {}
22: constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {}
[NC-3] In functions which accept an address as a parameter, there should be a zero address check to prevent bugs
74
Implement a zero address check to ensure input isn't the zero address
Findings are labeled with ' <= FOUND'
Click to show findings
52: function getProposalEta(
53: address target,
54: bytes calldata callData,
55: uint256 nativeValue
56: ) external view returns (uint256)
68: function executeProposal(
69: address target,
70: bytes calldata callData,
71: uint256 nativeValue
72: ) external payable
113: function _processCommand(
114: uint256 commandId,
115: address target,
116: bytes memory callData,
117: uint256 nativeValue,
118: uint256 eta
119: ) internal virtual
143: function _getProposalHash(
144: address target,
145: bytes memory callData,
146: uint256 nativeValue
147: ) internal pure returns (bytes32)
48: function executeMultisigProposal(
49: address target,
50: bytes calldata callData,
51: uint256 nativeValue
52: ) external payable onlySigners
72: function _processCommand(
73: uint256 commandId,
74: address target,
75: bytes memory callData,
76: uint256 nativeValue,
77: uint256 eta
78: ) internal override
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L103-L103
103: function isSigner(address account) external view override returns (bool)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L111-L111
111: function hasSignerVoted(address account, bytes32 topic) external view override returns (bool)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L142-L142
142: function rotateSigners(address[] memory newAccounts, uint256 newThreshold) external virtual onlySigners
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L149-L149
149: function _rotateSigners(address[] memory newAccounts, uint256 newThreshold) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L30-L30
30: function execute(
31: address target,
32: bytes calldata callData,
33: uint256 nativeValue
34: ) external payable onlySigners
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Caller.sol#L11-L11
11: function _call(
12: address target,
13: bytes calldata callData,
14: uint256 nativeValue
15: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L125-L125
125: function isContractCallApproved(
126: bytes32 commandId,
127: string calldata sourceChain,
128: string calldata sourceAddress,
129: address contractAddress,
130: bytes32 payloadHash
131: ) external view override returns (bool)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L135-L135
135: function isContractCallAndMintApproved(
136: bytes32 commandId,
137: string calldata sourceChain,
138: string calldata sourceAddress,
139: address contractAddress,
140: bytes32 payloadHash,
141: string calldata symbol,
142: uint256 amount
143: ) external view override returns (bool)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L253-L253
253: function transferGovernance(address newGovernance) external override onlyGovernance
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L259-L259
259: function transferMintLimiter(address newMintLimiter) external override onlyMintLimiter
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L279-L279
279: function upgrade(
280: address newImplementation,
281: bytes32 newImplementationCodeHash,
282: bytes calldata setupParams
283: ) external override onlyGovernance
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L504-L504
504: function _hasCode(address addr) internal view returns (bool)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L511-L511
511: function _mintToken(
512: string memory symbol,
513: address account,
514: uint256 amount
515: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L529-L529
529: function _burnTokenFrom(
530: address sender,
531: string memory symbol,
532: uint256 amount
533: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L576-L576
576: function _getIsContractCallApprovedKey(
577: bytes32 commandId,
578: string memory sourceChain,
579: string memory sourceAddress,
580: address contractAddress,
581: bytes32 payloadHash
582: ) internal pure returns (bytes32)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L586-L586
586: function _getIsContractCallApprovedWithMintKey(
587: bytes32 commandId,
588: string memory sourceChain,
589: string memory sourceAddress,
590: address contractAddress,
591: bytes32 payloadHash,
592: string memory symbol,
593: uint256 amount
594: ) internal pure returns (bytes32)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L643-L643
643: function _setTokenAddress(string memory symbol, address tokenAddress) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L651-L651
651: function _setContractCallApproved(
652: bytes32 commandId,
653: string memory sourceChain,
654: string memory sourceAddress,
655: address contractAddress,
656: bytes32 payloadHash
657: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L661-L661
661: function _setContractCallApprovedWithMint(
662: bytes32 commandId,
663: string memory sourceChain,
664: string memory sourceAddress,
665: address contractAddress,
666: bytes32 payloadHash,
667: string memory symbol,
668: uint256 amount
669: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L676-L676
676: function _setImplementation(address newImplementation) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L680-L680
680: function _transferGovernance(address newGovernance) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L686-L686
686: function _transferMintLimiter(address newMintLimiter) internal
92: function setWhitelistedProposalCaller(
93: string calldata sourceChain,
94: address sourceCaller,
95: bool whitelisted
96: ) external override onlyOwner
107: function setWhitelistedProposalSender(
108: string calldata sourceChain,
109: address sourceSender,
110: bool whitelisted
111: ) external override onlyOwner
142: function _onProposalExecuted(
143: string calldata,
144: string calldata,
145: address,
146: bytes calldata payload
147: ) internal virtual
58: function deployedAddress(
59: bytes calldata bytecode,
60: address sender,
61: bytes32 salt
62: ) external view returns (address deployedAddress_)
67: function deployedAddress(address sender, bytes32 salt) external view returns (address)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L71-L71
71: function deployedAddress(address sender, bytes32 salt) internal pure returns (address deployed)
52: function upgrade(
53: address newImplementation,
54: bytes32 newImplementationCodeHash,
55: bytes calldata params
56: ) external override onlyOwner
79: function interchainTransferFrom(
80: address sender,
81: string calldata destinationChain,
82: bytes calldata recipient,
83: uint256 amount,
84: bytes calldata metadata
85: ) external payable
202: function getCanonicalTokenId(address tokenAddress) public view returns (bytes32 tokenId)
213: function getCustomTokenId(address sender, bytes32 salt) public pure returns (bytes32 tokenId)
241: function getParamsLockUnlock(bytes memory operator, address tokenAddress) public pure returns (bytes memory params)
251: function getParamsMintBurn(bytes memory operator, address tokenAddress) public pure returns (bytes memory params)
262: function getParamsLiquidityPool(
263: bytes memory operator,
264: address tokenAddress,
265: address liquidityPoolAddress
266: ) public pure returns (bytes memory params)
309: function registerCanonicalToken(address tokenAddress) external payable notPaused returns (bytes32 tokenId)
388: function deployAndRegisterStandardizedToken(
389: bytes32 salt,
390: string calldata name,
391: string calldata symbol,
392: uint8 decimals,
393: uint256 mintAmount,
394: address distributor
395: ) external payable notPaused
439: function expressReceiveToken(
440: bytes32 tokenId,
441: address destinationAddress,
442: uint256 amount,
443: bytes32 commandId
444: ) external
467: function expressReceiveTokenWithData(
468: bytes32 tokenId,
469: string memory sourceChain,
470: bytes memory sourceAddress,
471: address destinationAddress,
472: uint256 amount,
473: bytes calldata data,
474: bytes32 commandId
475: ) external
502: function transmitSendToken(
503: bytes32 tokenId,
504: address sourceAddress,
505: string calldata destinationChain,
506: bytes memory destinationAddress,
507: uint256 amount,
508: bytes calldata metadata
509: ) external payable onlyTokenManager(tokenId) notPaused
559: function _sanitizeTokenManagerImplementation(address[] memory implementaions, TokenManagerType tokenManagerType)
560: internal
561: pure
562: returns (address implementation)
563:
707: function _callContract(
708: string calldata destinationChain,
709: bytes memory payload,
710: uint256 gasValue,
711: address refundTo
712: ) internal
726: function _validateToken(address tokenAddress)
727: internal
728: returns (
729: string memory name,
730: string memory symbol,
731: uint8 decimals
732: )
733:
841: function _deployStandardizedToken(
842: bytes32 tokenId,
843: address distributor,
844: string memory name,
845: string memory symbol,
846: uint8 decimals,
847: uint256 mintAmount,
848: address mintTo
849: ) internal
880: function _expressExecuteWithInterchainTokenToken(
881: bytes32 tokenId,
882: address destinationAddress,
883: string memory sourceChain,
884: bytes memory sourceAddress,
885: bytes calldata data,
886: uint256 amount
887: ) internal
30: function toBytes(address addr) internal pure returns (bytes memory bytesAddress)
76: function mint(address account, uint256 amount) external onlyDistributor
86: function burn(address account, uint256 amount) external onlyDistributor
136: function transmitInterchainTransfer(
137: address sender,
138: string calldata destinationChain,
139: bytes calldata destinationAddress,
140: uint256 amount,
141: bytes calldata metadata
142: ) external payable virtual onlyToken
161: function giveToken(address destinationAddress, uint256 amount) external onlyService returns (uint256)
38: function _setTokenAddress(address tokenAddress_) internal
44: function _takeToken(address from, uint256 amount) internal override returns (uint256)
60: function _giveToken(address to, uint256 amount) internal override returns (uint256)
47: function _setLiquidityPool(address liquidityPool_) internal
67: function setLiquidityPool(address newLiquidityPool) external onlyOperator
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L39-L39
39: function _setDistributor(address distributor_) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L51-L51
51: function setDistributor(address distr) external onlyDistributor
26: function _getExpressReceiveTokenSlot(
27: bytes32 tokenId,
28: address destinationAddress,
29: uint256 amount,
30: bytes32 commandId
31: ) internal pure returns (uint256 slot)
46: function _getExpressReceiveTokenWithDataSlot(
47: bytes32 tokenId,
48: string memory sourceChain,
49: bytes memory sourceAddress,
50: address destinationAddress,
51: uint256 amount,
52: bytes memory data,
53: bytes32 commandId
54: ) internal pure returns (uint256 slot)
148: function getExpressReceiveToken(
149: bytes32 tokenId,
150: address destinationAddress,
151: uint256 amount,
152: bytes32 commandId
153: ) public view returns (address expressCaller)
171: function getExpressReceiveTokenWithData(
172: bytes32 tokenId,
173: string memory sourceChain,
174: bytes memory sourceAddress,
175: address destinationAddress,
176: uint256 amount,
177: bytes calldata data,
178: bytes32 commandId
179: ) public view returns (address expressCaller)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L39-L39
39: function _setOperator(address operator_) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L51-L51
51: function setOperator(address operator_) external onlyOperator
49: function deployStandardizedToken(
50: bytes32 salt,
51: address tokenManager,
52: address distributor,
53: string calldata name,
54: string calldata symbol,
55: uint8 decimals,
56: uint256 mintAmount,
57: address mintTo
58: ) external payable
35: function init(
36: address implementationAddress,
37: address newOwner,
38: bytes memory params
39: ) external
79: function _setExpressReceiveToken(
80: bytes32 tokenId,
81: address destinationAddress,
82: uint256 amount,
83: bytes32 commandId,
84: address expressCaller
85: ) internal
110: function _setExpressReceiveTokenWithData(
111: bytes32 tokenId,
112: string memory sourceChain,
113: bytes memory sourceAddress,
114: address destinationAddress,
115: uint256 amount,
116: bytes calldata data,
117: bytes32 commandId,
118: address expressCaller
119: ) internal
202: function _popExpressReceiveToken(
203: bytes32 tokenId,
204: address destinationAddress,
205: uint256 amount,
206: bytes32 commandId
207: ) internal returns (address expressCaller)
231: function _popExpressReceiveTokenWithData(
232: bytes32 tokenId,
233: string memory sourceChain,
234: bytes memory sourceAddress,
235: address destinationAddress,
236: uint256 amount,
237: bytes memory data,
238: bytes32 commandId
239: ) internal returns (address expressCaller)
2
In instances where a new variable is defined, there is no need to set it to it's default value.
Findings are labeled with ' <= FOUND'
Click to show findings
105: uint256 totalGas = 0; // <= FOUND
118: uint32 version = 0; // <= FOUND
1
In instances where a new variable is defined, there is no need to set it to it's default value.
Findings are labeled with ' <= FOUND'
Click to show findings
63: if (implementation_.code.length == 0) implementation_ = address(0); // <= FOUND
23
Constant keccak variables should be replaced with immutable variables in Solidity contracts to optimize gas usage and enhance efficiency. While constant variables are evaluated and computed at runtime, immutable variables are assigned during contract deployment and stored directly in the contract bytecode. By using immutable for keccak variables, their hash values are computed only once during deployment, reducing the gas cost associated with repeated computations at runtime. This approach leads to more efficient execution, conserving resources for users, and allowing for smoother contract interactions, ultimately benefiting the overall performance and user experience.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L13-L13
13: bytes32 internal constant PREFIX_TIME_LOCK = keccak256('time-lock'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L44-L44
44: bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L45-L45
45: bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L46-L46
46: bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L47-L47
47: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L48-L48
48: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L49-L49
49: bytes32 internal constant PREFIX_TOKEN_MINT_LIMIT = keccak256('token-mint-limit'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L50-L50
50: bytes32 internal constant PREFIX_TOKEN_MINT_AMOUNT = keccak256('token-mint-amount'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L52-L52
52: bytes32 internal constant SELECTOR_BURN_TOKEN = keccak256('burnToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L53-L53
53: bytes32 internal constant SELECTOR_DEPLOY_TOKEN = keccak256('deployToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L54-L54
54: bytes32 internal constant SELECTOR_MINT_TOKEN = keccak256('mintToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L55-L55
55: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL = keccak256('approveContractCall'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L56-L56
56: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT = keccak256('approveContractCallWithMint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L57-L57
57: bytes32 internal constant SELECTOR_TRANSFER_OPERATORSHIP = keccak256('transferOperatorship'); // <= FOUND
18: bytes32 internal constant FINAL_IMPLEMENTATION_SALT = keccak256('final-implementation'); // <= FOUND
62: bytes32 internal constant PREFIX_CUSTOM_TOKEN_ID = keccak256('its-custom-token-id'); // <= FOUND
63: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_ID = keccak256('its-standardized-token-id'); // <= FOUND
64: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_SALT = keccak256('its-standardized-token-salt'); // <= FOUND
71: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service'); // <= FOUND
12: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator'); // <= FOUND
27: bytes32 private constant CONTRACT_ID = keccak256('standardized-token'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L15-L15
15: uint256 internal constant PREFIX_FLOW_OUT_AMOUNT = uint256(keccak256('prefix-flow-out-amount')); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L16-L16
16: uint256 internal constant PREFIX_FLOW_IN_AMOUNT = uint256(keccak256('prefix-flow-in-amount')); // <= FOUND
23
Implement a zero address check to prevent wrong address assignation during deployment
Findings are labeled with ' <= FOUND'
Click to show findings
33: constructor(
34: address gateway,
35: string memory governanceChain_,
36: string memory governanceAddress_,
37: uint256 minimumTimeDelay
38: ) AxelarExecutable(gateway) TimeLock(minimumTimeDelay) {
39: governanceChain = governanceChain_;
40: governanceAddress = governanceAddress_;
41: governanceChainHash = keccak256(bytes(governanceChain_));
42: governanceAddressHash = keccak256(bytes(governanceAddress_));
43: }
33: constructor(
34: address gateway,
35: string memory governanceChain,
36: string memory governanceAddress,
37: uint256 minimumTimeDelay,
38: address[] memory cosigners,
39: uint256 threshold
40: ) InterchainGovernance(gateway, governanceChain, governanceAddress, minimumTimeDelay) MultisigBase(cosigners, threshold) {}
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L35-L35
35: constructor(address[] memory accounts, uint256 threshold) {
36: _rotateSigners(accounts, threshold);
37: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L20-L20
20: constructor(address[] memory accounts, uint256 threshold) MultisigBase(accounts, threshold) {}
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L64-L64
64: constructor(address authModule_, address tokenDeployerImplementation_) {
65: if (authModule_.code.length == 0) revert InvalidAuthModule();
66: if (tokenDeployerImplementation_.code.length == 0) revert InvalidTokenDeployer();
67:
68: AUTH_MODULE = authModule_;
69: TOKEN_DEPLOYER_IMPLEMENTATION = tokenDeployerImplementation_;
70: }
42: constructor(address _gateway, address _gasService) {
43: gateway = IAxelarGateway(_gateway);
44: gasService = IAxelarGasService(_gasService);
45: }
29: constructor(address _gateway, address _owner) AxelarExecutable(_gateway) {
30: _transferOwnership(_owner);
31: }
25: constructor(
26: address implementationAddress,
27: address owner,
28: bytes memory setupParams
29: ) {
30: if (owner == address(0)) revert InvalidOwner();
31:
32: bytes32 id = contractId();
33: if (id != bytes32(0) && IUpgradable(implementationAddress).contractId() != id) revert InvalidImplementation();
34:
35: assembly {
36: sstore(_IMPLEMENTATION_SLOT, implementationAddress)
37: sstore(_OWNER_SLOT, owner)
38: }
39:
40: if (setupParams.length != 0) {
41: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IUpgradable.setup.selector, setupParams));
42: if (!success) revert SetupFailed();
43: }
44: }
26: constructor(
27: address implementationAddress,
28: address owner,
29: bytes memory setupParams
30: ) Proxy(implementationAddress, owner, setupParams) {}
23: constructor(address implementationAddress) {
24: implementation = implementationAddress;
25: }
83: constructor(
84: address tokenManagerDeployer_,
85: address standardizedTokenDeployer_,
86: address gateway_,
87: address gasService_,
88: address remoteAddressValidator_,
89: address[] memory tokenManagerImplementations,
90: string memory chainName_
91: ) AxelarExecutable(gateway_) {
92: if (
93: remoteAddressValidator_ == address(0) ||
94: gasService_ == address(0) ||
95: tokenManagerDeployer_ == address(0) ||
96: standardizedTokenDeployer_ == address(0)
97: ) revert ZeroAddress();
98: remoteAddressValidator = IRemoteAddressValidator(remoteAddressValidator_);
99: gasService = IAxelarGasService(gasService_);
100: tokenManagerDeployer = tokenManagerDeployer_;
101: standardizedTokenDeployer = standardizedTokenDeployer_;
102: deployer = ITokenManagerDeployer(tokenManagerDeployer_).deployer();
103:
104: if (tokenManagerImplementations.length != uint256(type(TokenManagerType).max) + 1) revert LengthMismatch();
105:
106: implementationLockUnlock = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.LOCK_UNLOCK);
107: implementationMintBurn = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.MINT_BURN);
19: constructor(
20: address implementationAddress,
21: address owner,
22: address operator
23: ) FinalProxy(implementationAddress, owner, abi.encodePacked(operator)) {}
20: constructor(
21: address implementationAddress,
22: address owner,
23: bytes memory params
24: ) Proxy(implementationAddress, owner, params) {}
21: constructor(address implementationAddress, bytes memory params) FixedProxy(implementationAddress) {
22: if (IStandardizedToken(implementationAddress).contractId() != CONTRACT_ID) revert InvalidImplementation();
23:
24: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IStandardizedToken.setup.selector, params));
25: if (!success) revert SetupFailed();
26: }
25: constructor(
26: address interchainTokenServiceAddress_,
27: uint256 implementationType_,
28: bytes32 tokenId_,
29: bytes memory params
30: ) {
31: interchainTokenServiceAddress = IInterchainTokenService(interchainTokenServiceAddress_);
32: implementationType = implementationType_;
33: tokenId = tokenId_;
34: address impl = _getImplementation(IInterchainTokenService(interchainTokenServiceAddress_), implementationType_);
35:
36: (bool success, ) = impl.delegatecall(abi.encodeWithSelector(TokenManagerProxy.setup.selector, params));
37: if (!success) revert SetupFailed();
38: }
27: constructor(address _interchainTokenServiceAddress) {
28: if (_interchainTokenServiceAddress == address(0)) revert ZeroAddress();
29: interchainTokenServiceAddress = _interchainTokenServiceAddress;
30: interchainTokenServiceAddressHash = keccak256(bytes(_lowerCase(interchainTokenServiceAddress.toString())));
31: }
27: constructor(address interchainTokenService_) {
28: if (interchainTokenService_ == address(0)) revert TokenLinkerZeroAddress();
29: interchainTokenService = IInterchainTokenService(interchainTokenService_);
30: }
19: constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {}
22: constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {}
26: constructor(
27: address deployer_,
28: address implementationLockUnlockAddress_,
29: address implementationMintBurnAddress_
30: ) {
31: if (deployer_ == address(0) || implementationLockUnlockAddress_ == address(0) || implementationMintBurnAddress_ == address(0))
32: revert AddressZero();
33: deployer = Create3Deployer(deployer_);
34: implementationLockUnlockAddress = implementationLockUnlockAddress_;
35: implementationMintBurnAddress = implementationMintBurnAddress_;
36: }
22: constructor(address deployer_) {
23: if (deployer_ == address(0)) revert AddressZero();
24: deployer = Create3Deployer(deployer_);
25: }
1
Ownable2Step further prevents risks posed by centralised privileges as there is a smaller likelihood of the owner being wrongfully changed
Findings are labeled with ' <= FOUND'
Click to show findings
22: contract InterchainProposalExecutor is IInterchainProposalExecutor, AxelarExecutable, Ownable // <= FOUND
7
Add a preceding underscore to the function name, take care to refactor where there functions are called
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L51-L51
51: function deploy(bytes32 salt, bytes memory bytecode) internal returns (address deployed)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L71-L71
71: function deployedAddress(address sender, bytes32 salt) internal pure returns (address deployed)
39: function contractId() internal pure virtual returns (bytes32)
17: function toAddress(bytes memory bytesAddress) internal pure returns (address addr)
30: function toBytes(address addr) internal pure returns (bytes memory bytesAddress)
30: function contractId() internal pure override returns (bytes32)
[NC-10] Private and internal state variables should have a preceding _ in their name unless they are constants
9
Add a preceding underscore to the state variable name, take care to refactor where there variables are read/wrote
Findings are labeled with ' <= FOUND'
Click to show findings
13: address private immutable implementationAddress; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L60-L60
60: address internal immutable AUTH_MODULE; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L62-L62
62: address internal immutable TOKEN_DEPLOYER_IMPLEMENTATION; // <= FOUND
51: address internal immutable implementationLockUnlock; // <= FOUND
52: address internal immutable implementationMintBurn; // <= FOUND
53: address internal immutable implementationLiquidityPool; // <= FOUND
59: bytes32 internal immutable chainNameHash; // <= FOUND
60: bytes32 internal immutable chainName; // <= FOUND
15: address internal immutable implementationAddress; // <= FOUND
113
Consider spreading these lines over multiple lines to aid in readability and the support of VIM users everywhere.
Findings are labeled with ' <= FOUND'
Click to show findings
18: event ProposalScheduled(bytes32 indexed proposalHash, address indexed target, bytes callData, uint256 value, uint256 indexed eta); // <= FOUND
19: event ProposalCancelled(bytes32 indexed proposalHash, address indexed target, bytes callData, uint256 value, uint256 indexed eta); // <= FOUND
20: event ProposalExecuted(bytes32 indexed proposalHash, address indexed target, bytes callData, uint256 value, uint256 indexed timestamp); // <= FOUND
92: if (keccak256(bytes(sourceChain)) != governanceChainHash || keccak256(bytes(sourceAddress)) != governanceAddressHash) // <= FOUND
95: (uint256 command, address target, bytes memory callData, uint256 nativeValue, uint256 eta) = abi.decode( // <= FOUND
15: event MultisigApproved(bytes32 indexed proposalHash, address indexed targetContract, bytes callData, uint256 nativeValue); // <= FOUND
16: event MultisigCancelled(bytes32 indexed proposalHash, address indexed targetContract, bytes callData, uint256 nativeValue); // <= FOUND
17: event MultisigExecuted(bytes32 indexed proposalHash, address indexed targetContract, bytes callData, uint256 nativeValue); // <= FOUND
40: ) InterchainGovernance(gateway, governanceChain, governanceAddress, minimumTimeDelay) MultisigBase(cosigners, threshold) {} // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L35-L35
35: bytes32 internal constant KEY_IMPLEMENTATION = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L38-L38
38: bytes32 internal constant KEY_GOVERNANCE = bytes32(0xabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L41-L41
41: bytes32 internal constant KEY_MINT_LIMITER = bytes32(0x627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L48-L48
48: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L56-L56
56: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT = keccak256('approveContractCallWithMint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L87-L87
87: if (msg.sender != getAddress(KEY_MINT_LIMITER) && msg.sender != getAddress(KEY_GOVERNANCE)) revert NotMintLimiter(); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L111-L111
111: emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L122-L122
122: emit ContractCallWithToken(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload, symbol, amount); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L132-L132
132: return getBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L146-L146
146: _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L156-L156
156: bytes32 key = _getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L169-L169
169: bytes32 key = _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash, symbol, amount); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L265-L265
265: function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external override onlyMintLimiter { // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L293-L293
293: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(IAxelarGateway.setup.selector, setupParams)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L310-L310
310: (address governance_, address mintLimiter_, bytes memory newOperatorsData) = abi.decode(params, (address, address, bytes)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L373-L373
373: (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L385-L385
385: (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode( // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L421-L421
421: (string memory symbol, address account, uint256 amount) = abi.decode(params, (string, address, uint256)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L434-L434
434: address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode))); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L442-L442
442: abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler))) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L445-L445
445: if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L465-L465
465: emit ContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, sourceTxHash, sourceEventIndex); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L480-L480
480: _setContractCallApprovedWithMint(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L508-L508
508: return codehash != bytes32(0) && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L544-L544
544: IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IBurnableMintableCappedERC20.burnFrom.selector, sender, amount)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L546-L546
546: IERC20(tokenAddress).safeTransferFrom(sender, IBurnableMintableCappedERC20(tokenAddress).depositAddress(bytes32(0)), amount); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L583-L583
583: return keccak256(abi.encode(PREFIX_CONTRACT_CALL_APPROVED, commandId, sourceChain, sourceAddress, contractAddress, payloadHash)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L615-L615
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash))))); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L658-L658
658: _setBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash), true); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L671-L671
671: _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount), // <= FOUND
59: function sendProposals(InterchainCalls.InterchainCall[] calldata interchainCalls) external payable override { // <= FOUND
85: _sendProposal(InterchainCalls.InterchainCall(destinationChain, destinationContract, msg.value, calls)); // <= FOUND
54: (address interchainProposalCaller, InterchainCalls.Call[] memory calls) = abi.decode(payload, (address, InterchainCalls.Call[])); // <= FOUND
66: emit ProposalExecuted(keccak256(abi.encode(sourceChain, sourceAddress, interchainProposalCaller, payload))); // <= FOUND
7: event WhitelistedProposalCallerSet(string indexed sourceChain, address indexed sourceCaller, bool whitelisted); // <= FOUND
10: event WhitelistedProposalSenderSet(string indexed sourceChain, address indexed sourceSender, bool whitelisted); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L72-L72
72: address deployer = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', sender, salt, DEPLOYER_BYTECODE_HASH))))); // <= FOUND
14: bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; // <= FOUND
16: bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0; // <= FOUND
50: if (id != bytes32(0) && IUpgradable(implementationAddress).contractId() != id) revert InvalidImplementation(); // <= FOUND
41: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IUpgradable.setup.selector, setupParams)); // <= FOUND
57: if (IUpgradable(newImplementation).contractId() != IUpgradable(this).contractId()) revert InvalidImplementation(); // <= FOUND
61: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params)); // <= FOUND
58: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IUpgradable.setup.selector, params)); // <= FOUND
72: function finalUpgrade(bytes memory bytecode, bytes calldata setupParams) public returns (address finalImplementation_) { // <= FOUND
81: (bool success, ) = finalImplementation_.delegatecall(abi.encodeWithSelector(BaseProxy.setup.selector, setupParams)); // <= FOUND
66: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata); // <= FOUND
104: if (tokenManagerImplementations.length != uint256(type(TokenManagerType).max) + 1) revert LengthMismatch(); // <= FOUND
106: implementationLockUnlock = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.LOCK_UNLOCK); // <= FOUND
107: implementationMintBurn = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.MINT_BURN); // <= FOUND
108: implementationLiquidityPool = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.LIQUIDITY_POOL); // <= FOUND
172: if (ITokenManagerProxy(tokenManagerAddress).tokenId() != tokenId) revert TokenManagerDoesNotExist(tokenId); // <= FOUND
241: function getParamsLockUnlock(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) { // <= FOUND
251: function getParamsMintBurn(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) { // <= FOUND
309: function registerCanonicalToken(address tokenAddress) external payable notPaused returns (bytes32 tokenId) { // <= FOUND
313: _deployTokenManager(tokenId, TokenManagerType.LOCK_UNLOCK, abi.encode(address(this).toBytes(), tokenAddress)); // <= FOUND
333: (string memory tokenName, string memory tokenSymbol, uint8 tokenDecimals) = _validateToken(tokenAddress); // <= FOUND
334: _deployRemoteStandardizedToken(tokenId, tokenName, tokenSymbol, tokenDecimals, '', '', destinationChain, gasValue); // <= FOUND
399: TokenManagerType tokenManagerType = distributor == tokenManagerAddress ? TokenManagerType.MINT_BURN : TokenManagerType.LOCK_UNLOCK; // <= FOUND
428: _deployRemoteStandardizedToken(tokenId, name, symbol, decimals, distributor, operator, destinationChain, gasValue); // <= FOUND
484: _expressExecuteWithInterchainTokenToken(tokenId, destinationAddress, sourceChain, sourceAddress, data, amount); // <= FOUND
486: _setExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, caller); // <= FOUND
520: payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata); // <= FOUND
522: emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata); // <= FOUND
559: function _sanitizeTokenManagerImplementation(address[] memory implementaions, TokenManagerType tokenManagerType) // <= FOUND
566: if (ITokenManager(implementation).implementationType() != uint256(tokenManagerType)) revert InvalidTokenManagerImplementation(); // <= FOUND
600: (, bytes32 tokenId, bytes memory destinationAddressBytes, uint256 amount) = abi.decode(payload, (uint256, bytes32, bytes, uint256)); // <= FOUND
658: IInterchainTokenExpressExecutable(destinationAddress).executeWithInterchainToken(sourceChain, sourceAddress, data, tokenId, amount); // <= FOUND
690: address distributor = distributorBytes.length > 0 ? distributorBytes.toAddress() : tokenManagerAddress; // <= FOUND
757: emit RemoteTokenManagerDeploymentInitialized(tokenId, destinationChain, gasValue, tokenManagerType, params); // <= FOUND
814: abi.encodeWithSelector(ITokenManagerDeployer.deployTokenManager.selector, tokenId, tokenManagerType, params) // <= FOUND
872: function _decodeMetadata(bytes calldata metadata) internal pure returns (uint32 version, bytes calldata data) { // <= FOUND
14: interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAxelarExecutable, IPausable, IMulticall { // <= FOUND
32: event TokenSent(bytes32 tokenId, string destinationChain, bytes destinationAddress, uint256 indexed amount); // <= FOUND
41: event TokenReceived(bytes32 indexed tokenId, string sourceChain, address indexed destinationAddress, uint256 indexed amount); // <= FOUND
67: event TokenManagerDeployed(bytes32 indexed tokenId, TokenManagerType indexed tokenManagerType, bytes params); // <= FOUND
145: function getParamsLockUnlock(bytes memory operator, address tokenAddress) external pure returns (bytes memory params); // <= FOUND
153: function getParamsMintBurn(bytes memory operator, address tokenAddress) external pure returns (bytes memory params); // <= FOUND
22: if (IStandardizedToken(implementationAddress).contractId() != CONTRACT_ID) revert InvalidImplementation(); // <= FOUND
24: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IStandardizedToken.setup.selector, params)); // <= FOUND
34: address impl = _getImplementation(IInterchainTokenService(interchainTokenServiceAddress_), implementationType_); // <= FOUND
36: (bool success, ) = impl.delegatecall(abi.encodeWithSelector(TokenManagerProxy.setup.selector, params)); // <= FOUND
54: function _getImplementation(IInterchainTokenService interchainTokenServiceAddress_, uint256 implementationType_) // <= FOUND
30: interchainTokenServiceAddressHash = keccak256(bytes(_lowerCase(interchainTokenServiceAddress.toString()))); // <= FOUND
41: (string[] memory trustedChainNames, string[] memory trustedAddresses) = abi.decode(params, (string[], string[])); // <= FOUND
69: function validateSender(string calldata sourceChain, string calldata sourceAddress) external view returns (bool) { // <= FOUND
25: function validateSender(string calldata sourceChain, string calldata sourceAddress) external view returns (bool); // <= FOUND
54: (tokenManager_, distributor_, tokenName, symbol, decimals) = abi.decode(params, (address, address, string, string, uint8)); // <= FOUND
63: (, , , , , mintAmount, mintTo) = abi.decode(params, (address, address, string, string, uint8, uint256, address)); // <= FOUND
22: uint256 internal constant TOKEN_ADDRESS_SLOT = 0xc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42ba; // <= FOUND
48: SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20BurnableMintable.burn.selector, from, amount)); // <= FOUND
62: SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20BurnableMintable.mint.selector, to, amount)); // <= FOUND
19: uint256 internal constant LIQUIDITY_POOL_SLOT = 0x8e02741a3381812d092c5689c9fc701c5185c1742fdf7954c4c4472be4cc4807; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L15-L15
15: uint256 internal constant DISTRIBUTOR_SLOT = 0x71c5a35e45a25c49e8f747acd4bcb869814b3d104c492d2554f4c46e12371f56; // <= FOUND
14: uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN = 0x67c7b41c1cb0375e36084c4ec399d005168e83425fa471b9224f6115af865619; // <= FOUND
16: uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA = 0x3e607cc12a253b1d9f677a03d298ad869a90a8ba4bd0fb5739e7d79db7cdeaad; // <= FOUND
32: slot = uint256(keccak256(abi.encode(PREFIX_EXPRESS_RECEIVE_TOKEN, tokenId, destinationAddress, amount, commandId))); // <= FOUND
137: emit ExpressReceiveWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, expressCaller); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L14-L14
14: uint256 internal constant FLOW_LIMIT_SLOT = 0x201b7a0b7c19aaddc4ce9579b7df8d2db123805861bc7763627f13e04d8af42f; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L15-L15
15: uint256 internal constant OPERATOR_SLOT = 0xf23ec0bb4210edd5cba85afd05127efcd2fc6a781bfed49188da1081670b22d7; // <= FOUND
31: if (deployer_ == address(0) || implementationLockUnlockAddress_ == address(0) || implementationMintBurnAddress_ == address(0)) // <= FOUND
60: address implementationAddress = distributor == tokenManager ? implementationMintBurnAddress : implementationLockUnlockAddress; // <= FOUND
62: bytes memory params = abi.encode(tokenManager, distributor, name, symbol, decimals, mintAmount, mintTo); // <= FOUND
63: bytecode = abi.encodePacked(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params)); // <= FOUND
145
Newer solidity versions have new functionality and are generally more gas efficient too (0.8.19) as such it makes sense to use them provided it is safe to do so
Findings are labeled with ' <= FOUND'
Click to show findings
3: pragma solidity ^0.8.0; // <= FOUND
3: pragma solidity ^0.8.9;
[NC-13] Explicitly define visibility of state variables to prevent misconceptions on what can access the variable
1
Such state variables should be marked as private as this is the default visibility
Findings are labeled with ' <= FOUND'
Click to show findings
14: ExpressCallHandler,
48
In Solidity, while function overriding allows for functions with the same name to coexist, it is advisable to avoid this practice to enhance code readability and maintainability. Having multiple functions with the same name, even with different parameters or in inherited contracts, can cause confusion and increase the likelihood of errors during development, testing, and debugging. Using distinct and descriptive function names not only clarifies the purpose and behavior of each function, but also helps prevent unintended function calls or incorrect overriding. By adopting a clear and consistent naming convention, developers can create more comprehensible and maintainable smart contracts.
Findings are labeled with ' <= FOUND'
Click to show findings
113: function _processCommand( // <= FOUND
114: uint256 commandId,
115: address target,
116: bytes memory callData,
117: uint256 nativeValue,
118: uint256 eta
119: ) internal virtual
72: function _processCommand( // <= FOUND
73: uint256 commandId,
74: address target,
75: bytes memory callData,
76: uint256 nativeValue,
77: uint256 eta
78: ) internal override
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L30-L30
30: function execute( // <= FOUND
31: address target,
32: bytes calldata callData,
33: uint256 nativeValue
34: ) external payable onlySigners
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L322-L322
322: function execute(bytes calldata input) external override // <= FOUND
41: function _execute( // <= FOUND
42: string calldata sourceChain,
43: string calldata sourceAddress,
44: bytes calldata payload
45: ) internal override
575: function _execute( // <= FOUND
576: string calldata sourceChain,
577: string calldata sourceAddress,
578: bytes calldata payload
579: ) internal override onlyRemoteService(sourceChain, sourceAddress) notPaused
24: function deploy(bytes memory bytecode, bytes32 salt) external returns (address deployedAddress_) // <= FOUND
29: function deploy(bytes calldata bytecode, bytes32 salt) external returns (address deployedAddress_) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L21-L21
21: function deploy(bytes memory bytecode) external // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L51-L51
51: function deploy(bytes32 salt, bytes memory bytecode) internal returns (address deployed) // <= FOUND
42: function deployAndInit( // <= FOUND
43: bytes memory bytecode,
44: bytes32 salt,
45: bytes calldata init
46: ) external returns (address deployedAddress_)
58: function deployedAddress( // <= FOUND
59: bytes calldata bytecode,
60: address sender,
61: bytes32 salt
62: ) external view returns (address deployedAddress_)
67: function deployedAddress(address sender, bytes32 salt) external view returns (address) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L71-L71
71: function deployedAddress(address sender, bytes32 salt) internal pure returns (address deployed) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L227-L227
227: function implementation() public view override returns (address) // <= FOUND
22: function implementation() public view virtual returns (address implementation_) // <= FOUND
39: function implementation() public view returns (address implementation_) // <= FOUND
37: function implementation() public view override(BaseProxy, IProxy) returns (address implementation_) // <= FOUND
44: function implementation() public view returns (address impl) // <= FOUND
61: function setup(bytes calldata params) external override // <= FOUND
61: function setup(bytes calldata params) external // <= FOUND
78: function setup(bytes calldata data) external override onlyProxy // <= FOUND
31: function setup(bytes calldata setupParams) external // <= FOUND
61: function setup(bytes calldata params) external override onlyProxy // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L245-L245
245: function contractId() public pure returns (bytes32) // <= FOUND
39: function contractId() internal pure virtual returns (bytes32) // <= FOUND
36: function contractId() external pure returns (bytes32) // <= FOUND
30: function contractId() internal pure override returns (bytes32) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L279-L279
279: function upgrade( // <= FOUND
280: address newImplementation,
281: bytes32 newImplementationCodeHash,
282: bytes calldata setupParams
283: ) external override onlyGovernance
52: function upgrade( // <= FOUND
53: address newImplementation,
54: bytes32 newImplementationCodeHash,
55: bytes calldata params
56: ) external override onlyOwner
87: function _setup(bytes calldata data) internal virtual // <= FOUND
40: function _setup(bytes calldata params) internal override // <= FOUND
8: function tokenManagerRequiresApproval() public pure override returns (bool) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L96-L96
96: function sendToken( // <= FOUND
97: string calldata destinationChain,
98: string calldata destinationAddress,
99: string calldata symbol,
100: uint256 amount
101: ) external
83: function sendToken( // <= FOUND
84: string calldata destinationChain,
85: bytes calldata destinationAddress,
86: uint256 amount,
87: bytes calldata metadata
88: ) external payable virtual
534: function setFlowLimit(bytes32[] calldata tokenIds, uint256[] calldata flowLimits) external onlyOperator // <= FOUND
171: function setFlowLimit(uint256 flowLimit) external onlyOperator // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L643-L643
643: function _setTokenAddress(string memory symbol, address tokenAddress) internal // <= FOUND
38: function _setTokenAddress(address tokenAddress_) internal // <= FOUND
24: function implementationType() external pure returns (uint256) // <= FOUND
44: function _takeToken(address from, uint256 amount) internal override returns (uint256) // <= FOUND
60: function _giveToken(address to, uint256 amount) internal override returns (uint256) // <= FOUND
275: function getFlowLimit(bytes32 tokenId) external view returns (uint256 flowLimit) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L24-L24
24: function getFlowLimit() public view returns (uint256 flowLimit) // <= FOUND
285: function getFlowOutAmount(bytes32 tokenId) external view returns (uint256 flowOutAmount) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L63-L63
63: function getFlowOutAmount() external view returns (uint256 flowOutAmount) // <= FOUND
295: function getFlowInAmount(bytes32 tokenId) external view returns (uint256 flowInAmount) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L75-L75
75: function getFlowInAmount() external view returns (uint256 flowInAmount) // <= FOUND
1
Overly complex code can make understanding functionality more difficult, try to further modularise your code to ensure readability
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L322-L322
322: function execute(bytes calldata input) external override // <= FOUND
67
This is to ensure the whole API is extracted in a interface
Findings are labeled with ' <= FOUND'
Click to show findings
52: function getProposalEta(
53: address target,
54: bytes calldata callData,
55: uint256 nativeValue
56: ) external view returns (uint256)
68: function executeProposal(
69: address target,
70: bytes calldata callData,
71: uint256 nativeValue
72: ) external payable
48: function executeMultisigProposal(
49: address target,
50: bytes calldata callData,
51: uint256 nativeValue
52: ) external payable onlySigners
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L142-L142
142: function rotateSigners(address[] memory newAccounts, uint256 newThreshold) external virtual onlySigners
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L30-L30
30: function execute(
31: address target,
32: bytes calldata callData,
33: uint256 nativeValue
34: ) external payable onlySigners
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L96-L96
96: function sendToken(
97: string calldata destinationChain,
98: string calldata destinationAddress,
99: string calldata symbol,
100: uint256 amount
101: ) external
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L106-L106
106: function callContract(
107: string calldata destinationChain,
108: string calldata destinationContractAddress,
109: bytes calldata payload
110: ) external
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L114-L114
114: function callContractWithToken(
115: string calldata destinationChain,
116: string calldata destinationContractAddress,
117: bytes calldata payload,
118: string calldata symbol,
119: uint256 amount
120: ) external
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L384-L384
384: function deployToken(bytes calldata params, bytes32) external onlySelf
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L420-L420
420: function mintToken(bytes calldata params, bytes32) external onlySelf
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L426-L426
426: function burnToken(bytes calldata params, bytes32) external onlySelf
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L454-L454
454: function approveContractCall(bytes calldata params, bytes32 commandId) external onlySelf
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L468-L468
468: function approveContractCallWithMint(bytes calldata params, bytes32 commandId) external onlySelf
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L494-L494
494: function transferOperatorship(bytes calldata newOperatorsData, bytes32) external onlySelf
24: function deploy(bytes memory bytecode, bytes32 salt) external returns (address deployedAddress_)
42: function deployAndInit(
43: bytes memory bytecode,
44: bytes32 salt,
45: bytes calldata init
46: ) external returns (address deployedAddress_)
58: function deployedAddress(
59: bytes calldata bytecode,
60: address sender,
61: bytes32 salt
62: ) external view returns (address deployedAddress_)
29: function deploy(bytes calldata bytecode, bytes32 salt) external returns (address deployedAddress_)
67: function deployedAddress(address sender, bytes32 salt) external view returns (address)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L21-L21
21: function deploy(bytes memory bytecode) external
61: function setup(bytes calldata params) external
35: function init(
36: address implementationAddress,
37: address newOwner,
38: bytes memory params
39: ) external
31: function setup(bytes calldata setupParams) external
43: function interchainTransfer(
44: string calldata destinationChain,
45: bytes calldata recipient,
46: uint256 amount,
47: bytes calldata metadata
48: ) external payable
79: function interchainTransferFrom(
80: address sender,
81: string calldata destinationChain,
82: bytes calldata recipient,
83: uint256 amount,
84: bytes calldata metadata
85: ) external payable
36: function contractId() external pure returns (bytes32)
180: function getTokenAddress(bytes32 tokenId) external view returns (address tokenAddress)
223: function getImplementation(uint256 tokenManagerType) external view returns (address tokenManagerAddress)
275: function getFlowLimit(bytes32 tokenId) external view returns (uint256 flowLimit)
285: function getFlowOutAmount(bytes32 tokenId) external view returns (uint256 flowOutAmount)
295: function getFlowInAmount(bytes32 tokenId) external view returns (uint256 flowInAmount)
309: function registerCanonicalToken(address tokenAddress) external payable notPaused returns (bytes32 tokenId)
365: function deployRemoteCustomTokenManager(
366: bytes32 salt,
367: string calldata destinationChain,
368: TokenManagerType tokenManagerType,
369: bytes calldata params,
370: uint256 gasValue
371: ) external payable notPaused returns (bytes32 tokenId)
388: function deployAndRegisterStandardizedToken(
389: bytes32 salt,
390: string calldata name,
391: string calldata symbol,
392: uint8 decimals,
393: uint256 mintAmount,
394: address distributor
395: ) external payable notPaused
417: function deployAndRegisterRemoteStandardizedToken(
418: bytes32 salt,
419: string calldata name,
420: string calldata symbol,
421: uint8 decimals,
422: bytes memory distributor,
423: bytes memory operator,
424: string calldata destinationChain,
425: uint256 gasValue
426: ) external payable notPaused
439: function expressReceiveToken(
440: bytes32 tokenId,
441: address destinationAddress,
442: uint256 amount,
443: bytes32 commandId
444: ) external
467: function expressReceiveTokenWithData(
468: bytes32 tokenId,
469: string memory sourceChain,
470: bytes memory sourceAddress,
471: address destinationAddress,
472: uint256 amount,
473: bytes calldata data,
474: bytes32 commandId
475: ) external
502: function transmitSendToken(
503: bytes32 tokenId,
504: address sourceAddress,
505: string calldata destinationChain,
506: bytes memory destinationAddress,
507: uint256 amount,
508: bytes calldata metadata
509: ) external payable onlyTokenManager(tokenId) notPaused
534: function setFlowLimit(bytes32[] calldata tokenIds, uint256[] calldata flowLimits) external onlyOperator
547: function setPaused(bool paused) external onlyOwner
69: function validateSender(string calldata sourceChain, string calldata sourceAddress) external view returns (bool)
95: function removeTrustedAddress(string calldata chain) external onlyOwner
106: function addGatewaySupportedChains(string[] calldata chainNames) external onlyOwner
119: function removeGatewaySupportedChains(string[] calldata chainNames) external onlyOwner
133: function getRemoteAddress(string calldata chainName) external view returns (string memory remoteAddress)
76: function mint(address account, uint256 amount) external onlyDistributor
86: function burn(address account, uint256 amount) external onlyDistributor
83: function sendToken(
84: string calldata destinationChain,
85: bytes calldata destinationAddress,
86: uint256 amount,
87: bytes calldata metadata
88: ) external payable virtual
109: function callContractWithInterchainToken(
110: string calldata destinationChain,
111: bytes calldata destinationAddress,
112: uint256 amount,
113: bytes calldata data
114: ) external payable virtual
136: function transmitInterchainTransfer(
137: address sender,
138: string calldata destinationChain,
139: bytes calldata destinationAddress,
140: uint256 amount,
141: bytes calldata metadata
142: ) external payable virtual onlyToken
161: function giveToken(address destinationAddress, uint256 amount) external onlyService returns (uint256)
171: function setFlowLimit(uint256 flowLimit) external onlyOperator
24: function implementationType() external pure returns (uint256)
67: function setLiquidityPool(address newLiquidityPool) external onlyOperator
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L51-L51
51: function setDistributor(address distr) external onlyDistributor
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L63-L63
63: function getFlowOutAmount() external view returns (uint256 flowOutAmount)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L75-L75
75: function getFlowInAmount() external view returns (uint256 flowInAmount)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L51-L51
51: function setOperator(address operator_) external onlyOperator
49: function deployStandardizedToken(
50: bytes32 salt,
51: address tokenManager,
52: address distributor,
53: string calldata name,
54: string calldata symbol,
55: uint8 decimals,
56: uint256 mintAmount,
57: address mintTo
58: ) external payable
33: function deployTokenManager(
34: bytes32 tokenId,
35: uint256 implementationType,
36: bytes calldata params
37: ) external payable
11
The following order should be used within contracts
constructor
receive function (if exists)
fallback function (if exists)
external
public
internal
private
Rearrange the contract functions and contructors to fit this ordering
Findings are labeled with ' <= FOUND'
Click to show findings
15: contract InterchainGovernance is AxelarExecutable, TimeLock, Caller, IInterchainGovernance // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L17-L17
17: contract AxelarGateway is IAxelarGateway, IGovernable, AdminMultisigBase // <= FOUND
22: contract InterchainProposalExecutor is IInterchainProposalExecutor, AxelarExecutable, Ownable // <= FOUND
17: contract FinalProxy is Proxy, IFinalProxy // <= FOUND
37: contract InterchainTokenService is
38: IInterchainTokenService,
39: AxelarExecutable,
40: Upgradable,
41: Operatable,
42: ExpressCallHandler,
43: Pausable,
44: Multicall
45:
13: contract TokenManagerProxy is ITokenManagerProxy // <= FOUND
12: contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable // <= FOUND
17: contract TokenManagerLiquidityPool is TokenManagerAddressStorage // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L13-L13
13: contract Distributable is IDistributable // <= FOUND
12: contract ExpressCallHandler is IExpressCallHandler // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L12-L12
12: contract FlowLimit is IFlowLimit // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L13-L13
13: contract Operatable is IOperatable // <= FOUND
13
If msg.sender play a part in the functionality of a function, any emits of this function should include msg.sender to ensure transparency with users
Findings are labeled with ' <= FOUND'
Click to show findings
29: function deploy(bytes calldata bytecode, bytes32 salt) external returns (address deployedAddress_) {
30: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt)); // <= FOUND
31: deployedAddress_ = Create3.deploy(deploySalt, bytecode);
32:
33: emit Deployed(keccak256(bytecode), salt, deployedAddress_); // <= FOUND
34: }
42: function deployAndInit(
43: bytes memory bytecode,
44: bytes32 salt,
45: bytes calldata init
46: ) external returns (address deployedAddress_) {
47: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt))); // <= FOUND
48:
49:
50: (bool success, ) = deployedAddress_.call(init);
51: if (!success) revert FailedInit();
52: }
49: function deployAndInit(
50: bytes memory bytecode,
51: bytes32 salt,
52: bytes calldata init
53: ) external returns (address deployedAddress_) {
54: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt)); // <= FOUND
55: deployedAddress_ = Create3.deploy(deploySalt, bytecode);
56:
57: (bool success, ) = deployedAddress_.call(init);
58: if (!success) revert FailedInit();
59:
60: emit Deployed(keccak256(bytecode), salt, deployedAddress_); // <= FOUND
61: }
343: function deployCustomTokenManager(
344: bytes32 salt,
345: TokenManagerType tokenManagerType,
346: bytes memory params
347: ) public payable notPaused returns (bytes32 tokenId) {
348: address deployer_ = msg.sender; // <= FOUND
349: tokenId = getCustomTokenId(deployer_, salt);
350: _deployTokenManager(tokenId, tokenManagerType, params);
351: emit CustomTokenIdClaimed(tokenId, deployer_, salt); // <= FOUND
352: }
365: function deployRemoteCustomTokenManager(
366: bytes32 salt,
367: string calldata destinationChain,
368: TokenManagerType tokenManagerType,
369: bytes calldata params,
370: uint256 gasValue
371: ) external payable notPaused returns (bytes32 tokenId) {
372: address deployer_ = msg.sender; // <= FOUND
373: tokenId = getCustomTokenId(deployer_, salt);
374: _deployRemoteTokenManager(tokenId, destinationChain, gasValue, tokenManagerType, params);
375: emit CustomTokenIdClaimed(tokenId, deployer_, salt); // <= FOUND
376: }
748: function _deployRemoteTokenManager(
749: bytes32 tokenId,
750: string calldata destinationChain,
751: uint256 gasValue,
752: TokenManagerType tokenManagerType,
753: bytes memory params
754: ) internal {
755: bytes memory payload = abi.encode(SELECTOR_DEPLOY_TOKEN_MANAGER, tokenId, tokenManagerType, params);
756: _callContract(destinationChain, payload, gasValue, msg.sender); // <= FOUND
757: emit RemoteTokenManagerDeploymentInitialized(tokenId, destinationChain, gasValue, tokenManagerType, params); // <= FOUND
758: }
770: function _deployRemoteStandardizedToken(
771: bytes32 tokenId,
772: string memory name,
773: string memory symbol,
774: uint8 decimals,
775: bytes memory distributor,
776: bytes memory operator,
777: string calldata destinationChain,
778: uint256 gasValue
779: ) internal {
780: bytes memory payload = abi.encode(
781: SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN,
782: tokenId,
783: name,
784: symbol,
785: decimals,
786: distributor,
787: operator
788: );
789: _callContract(destinationChain, payload, gasValue, msg.sender); // <= FOUND
790: emit RemoteStandardizedTokenAndManagerDeploymentInitialized( // <= FOUND
791: tokenId,
792: name,
793: symbol,
794: decimals,
795: distributor,
796: operator,
797: destinationChain,
798: gasValue
799: );
800: }
3
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L142-L142
142: function rotateSigners(address[] memory newAccounts, uint256 newThreshold) external virtual onlySigners {
143: _rotateSigners(newAccounts, newThreshold);
144: }
80: function sendProposal(
81: string memory destinationChain,
82: string memory destinationContract,
83: InterchainCalls.Call[] calldata calls
84: ) external payable override {
85: _sendProposal(InterchainCalls.InterchainCall(destinationChain, destinationContract, msg.value, calls));
86: }
559: function _sanitizeTokenManagerImplementation(address[] memory implementaions, TokenManagerType tokenManagerType)
560: internal
561: pure
562: returns (address implementation)
563: {
564: implementation = implementaions[uint256(tokenManagerType)];
565: if (implementation == address(0)) revert ZeroAddress();
566: if (ITokenManager(implementation).implementationType() != uint256(tokenManagerType)) revert InvalidTokenManagerImplementation();
567: }
76
Amend the ordering of imports to import interfaces first followed by other imports
Findings are labeled with ' <= FOUND'
Click to show findings
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { Create3Deployer } from '../../gmp-sdk/deploy/Create3Deployer.sol'; // <= FOUND
8:
9: import { IStandardizedTokenDeployer } from '../interfaces/IStandardizedTokenDeployer.sol'; // <= FOUND
10:
11: import { StandardizedTokenProxy } from '../proxies/StandardizedTokenProxy.sol'; // <= FOUND
12:
13:
14:
15:
16:
17: contract StandardizedTokenDeployer is IStandardizedTokenDeployer {
18: Create3Deployer public immutable deployer;
19: address public immutable implementationMintBurnAddress;
20: address public immutable implementationLockUnlockAddress;
21:
22:
23:
24:
25:
26:
27:
28: constructor(
29: address deployer_,
30: address implementationLockUnlockAddress_,
31: address implementationMintBurnAddress_
32: ) {
33: if (deployer_ == address(0) || implementationLockUnlockAddress_ == address(0) || implementationMintBurnAddress_ == address(0))
34: revert AddressZero();
35: deployer = Create3Deployer(deployer_);
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { ITokenManager } from '../interfaces/ITokenManager.sol'; // <= FOUND
8: import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol'; // <= FOUND
9: import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol'; // <= FOUND
10:
11: import { Operatable } from '../utils/Operatable.sol'; // <= FOUND
12: import { FlowLimit } from '../utils/FlowLimit.sol'; // <= FOUND
13: import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol'; // <= FOUND
14: import { Implementation } from '../utils/Implementation.sol'; // <= FOUND
15:
16:
17:
18:
19:
20: abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implementation {
21: using AddressBytesUtils for bytes;
22:
23: IInterchainTokenService public immutable interchainTokenService;
24:
25:
26:
27:
28:
29: constructor(address interchainTokenService_) {
30: if (interchainTokenService_ == address(0)) revert TokenLinkerZeroAddress();
31: interchainTokenService = IInterchainTokenService(interchainTokenService_);
32: }
33:
34:
35:
36:
37: modifier onlyService() {
38: if (msg.sender != address(interchainTokenService)) revert NotService();
2:
3: pragma solidity ^0.8.0;
4:
5: import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol'; // <= FOUND
6: import { StringToAddress } from '../gmp-sdk/util/AddressString.sol'; // <= FOUND
7: import { AxelarExecutable } from '../gmp-sdk/executable/AxelarExecutable.sol'; // <= FOUND
8: import { IInterchainProposalExecutor } from './interfaces/IInterchainProposalExecutor.sol'; // <= FOUND
9: import { InterchainCalls } from './lib/InterchainCalls.sol'; // <= FOUND
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23: contract InterchainProposalExecutor is IInterchainProposalExecutor, AxelarExecutable, Ownable {
24:
25: mapping(string => mapping(address => bool)) public whitelistedCallers;
26:
27:
28: mapping(string => mapping(address => bool)) public whitelistedSenders;
29:
30: constructor(address _gateway, address _owner) AxelarExecutable(_gateway) {
31: _transferOwnership(_owner);
32: }
33:
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; // <= FOUND
8: import { IERC20 } from '../../../gmp-sdk/interfaces/IERC20.sol'; // <= FOUND
9:
10: import { SafeTokenTransferFrom, SafeTokenTransfer } from '../../../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
11:
12:
13:
14:
15:
16:
17:
18: contract TokenManagerLockUnlock is TokenManagerAddressStorage {
19:
20:
21:
22:
23:
24: constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {}
25:
26: function implementationType() external pure returns (uint256) {
27: return 0;
28: }
29:
30:
31:
32:
33:
34: function _setup(bytes calldata params) internal override {
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { Create3Deployer } from '../../gmp-sdk/deploy/Create3Deployer.sol'; // <= FOUND
8:
9: import { ITokenManagerDeployer } from '../interfaces/ITokenManagerDeployer.sol'; // <= FOUND
10:
11: import { TokenManagerProxy } from '../proxies/TokenManagerProxy.sol'; // <= FOUND
12:
13:
14:
15:
16:
17: contract TokenManagerDeployer is ITokenManagerDeployer {
18: Create3Deployer public immutable deployer;
19:
20:
21:
22:
23:
24: constructor(address deployer_) {
25: if (deployer_ == address(0)) revert AddressZero();
26: deployer = Create3Deployer(deployer_);
27: }
28:
29:
30:
31:
32:
33:
34:
35: function deployTokenManager(
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { AxelarExecutable } from '../../gmp-sdk/executable/AxelarExecutable.sol'; // <= FOUND
8: import { TimeLock } from '../../gmp-sdk/util/TimeLock.sol'; // <= FOUND
9: import { IInterchainGovernance } from '../interfaces/IInterchainGovernance.sol'; // <= FOUND
10: import { Caller } from '../util/Caller.sol'; // <= FOUND
11:
12:
13:
14:
15:
16:
17: contract InterchainGovernance is AxelarExecutable, TimeLock, Caller, IInterchainGovernance {
18: enum GovernanceCommand {
19: ScheduleTimeLockProposal,
20: CancelTimeLockProposal
21: }
22:
23: string public governanceChain;
24: string public governanceAddress;
25: bytes32 public immutable governanceChainHash;
26: bytes32 public immutable governanceAddressHash;
27:
28:
29:
30:
31:
32:
33:
34:
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { IAxelarGateway } from '../../gmp-sdk/interfaces/IAxelarGateway.sol'; // <= FOUND
8: import { IAxelarGasService } from '../../gmp-sdk/interfaces/IAxelarGasService.sol'; // <= FOUND
9: import { AxelarExecutable } from '../../gmp-sdk/executable/AxelarExecutable.sol'; // <= FOUND
10: import { SafeTokenTransferFrom } from '../../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
11: import { IERC20 } from '../../gmp-sdk/interfaces/IERC20.sol'; // <= FOUND
12:
13: import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol'; // <= FOUND
14: import { ITokenManagerDeployer } from '../interfaces/ITokenManagerDeployer.sol'; // <= FOUND
15: import { IStandardizedTokenDeployer } from '../interfaces/IStandardizedTokenDeployer.sol'; // <= FOUND
16: import { IRemoteAddressValidator } from '../interfaces/IRemoteAddressValidator.sol'; // <= FOUND
17: import { IInterchainTokenExpressExecutable } from '../interfaces/IInterchainTokenExpressExecutable.sol'; // <= FOUND
18: import { ITokenManager } from '../interfaces/ITokenManager.sol'; // <= FOUND
19: import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol'; // <= FOUND
20: import { IERC20Named } from '../interfaces/IERC20Named.sol'; // <= FOUND
21:
22: import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol'; // <= FOUND
23: import { StringToBytes32, Bytes32ToString } from '../../gmp-sdk/util/Bytes32String.sol'; // <= FOUND
24:
25: import { Upgradable } from '../../gmp-sdk/upgradable/Upgradable.sol'; // <= FOUND
26: import { Create3Deployer } from '../../gmp-sdk/deploy/Create3Deployer.sol'; // <= FOUND
27:
28: import { ExpressCallHandler } from '../utils/ExpressCallHandler.sol'; // <= FOUND
29: import { Pausable } from '../utils/Pausable.sol'; // <= FOUND
30: import { Operatable } from '../utils/Operatable.sol'; // <= FOUND
31: import { Multicall } from '../utils/Multicall.sol'; // <= FOUND
32:
33:
34:
35:
36:
37:
38:
39: contract InterchainTokenService is
40: IInterchainTokenService,
41: AxelarExecutable,
42: Upgradable,
43: Operatable,
44: ExpressCallHandler,
45: Pausable,
46: Multicall
47: {
48: using StringToBytes32 for string;
49: using Bytes32ToString for bytes32;
50: using AddressBytesUtils for bytes;
51: using AddressBytesUtils for address;
52:
53: address internal immutable implementationLockUnlock;
54: address internal immutable implementationMintBurn;
55: address internal immutable implementationLiquidityPool;
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L7-L17
3:
4:
5: pragma solidity ^0.8.9;
6:
7: import { SafeTokenCall, SafeTokenTransfer, SafeTokenTransferFrom } from '../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
8: import { IERC20 } from '../gmp-sdk/interfaces/IERC20.sol'; // <= FOUND
9: import { IAxelarGateway } from './interfaces/IAxelarGateway.sol'; // <= FOUND
10: import { IGovernable } from './interfaces/IGovernable.sol'; // <= FOUND
11: import { IAxelarAuth } from './interfaces/IAxelarAuth.sol'; // <= FOUND
12: import { IBurnableMintableCappedERC20 } from './interfaces/IBurnableMintableCappedERC20.sol'; // <= FOUND
13: import { ITokenDeployer } from './interfaces/ITokenDeployer.sol'; // <= FOUND
14:
15: import { ECDSA } from './ECDSA.sol'; // <= FOUND
16: import { DepositHandler } from './DepositHandler.sol'; // <= FOUND
17: import { AdminMultisigBase } from './AdminMultisigBase.sol'; // <= FOUND
18:
19: contract AxelarGateway is IAxelarGateway, IGovernable, AdminMultisigBase {
20: using SafeTokenCall for IERC20;
21: using SafeTokenTransfer for IERC20;
22: using SafeTokenTransferFrom for IERC20;
23:
24: error InvalidImplementation();
25:
26: enum TokenType {
27: InternalBurnable,
28: InternalBurnableFrom,
29: External
30: }
31:
32:
33:
34:
35:
36:
37: bytes32 internal constant KEY_IMPLEMENTATION = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);
38:
39:
40: bytes32 internal constant KEY_GOVERNANCE = bytes32(0xabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909);
41:
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; // <= FOUND
8: import { IERC20BurnableMintable } from '../../interfaces/IERC20BurnableMintable.sol'; // <= FOUND
9:
10: import { IERC20 } from '../../../gmp-sdk/interfaces/IERC20.sol'; // <= FOUND
11: import { SafeTokenCall } from '../../../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
12:
13:
14:
15:
16:
17:
18:
19: contract TokenManagerMintBurn is TokenManagerAddressStorage {
20:
21:
22:
23:
24:
25: constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {}
26:
27: function implementationType() external pure returns (uint256) {
28: return 1;
29: }
30:
31:
32:
33:
34:
35: function _setup(bytes calldata params) internal override {
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { IERC20BurnableMintable } from '../interfaces/IERC20BurnableMintable.sol'; // <= FOUND
8:
9: import { InterchainToken } from '../interchain-token/InterchainToken.sol'; // <= FOUND
10: import { ERC20Permit } from '../token-implementations/ERC20Permit.sol'; // <= FOUND
11: import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol'; // <= FOUND
12: import { ITokenManager } from '../interfaces/ITokenManager.sol'; // <= FOUND
13: import { Implementation } from '../utils/Implementation.sol'; // <= FOUND
14: import { Distributable } from '../utils/Distributable.sol'; // <= FOUND
15:
16:
17:
18:
19:
20:
21: abstract contract StandardizedToken is InterchainToken, ERC20Permit, Implementation, Distributable {
22: using AddressBytesUtils for bytes;
23:
24: address public tokenManager;
25: string public name;
26: string public symbol;
27: uint8 public decimals;
28:
29: bytes32 private constant CONTRACT_ID = keccak256('standardized-token');
30:
31:
32:
33:
34: function contractId() external pure returns (bytes32) {
35: return CONTRACT_ID;
36: }
37:
38:
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { TokenManager } from '../TokenManager.sol'; // <= FOUND
8: import { IERC20 } from '../../../gmp-sdk/interfaces/IERC20.sol'; // <= FOUND
9: import { IAxelarGateway } from '../../../gmp-sdk/interfaces/IAxelarGateway.sol'; // <= FOUND
10:
11:
12:
13:
14:
15:
16: abstract contract TokenManagerAddressStorage is TokenManager {
17:
18:
19:
20:
21: constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {}
22:
23:
24: uint256 internal constant TOKEN_ADDRESS_SLOT = 0xc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42ba;
25:
26:
27:
28:
29:
30: function tokenAddress() public view override returns (address tokenAddress_) {
31: assembly {
32: tokenAddress_ := sload(TOKEN_ADDRESS_SLOT)
33: }
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; // <= FOUND
8: import { IERC20 } from '../../../gmp-sdk/interfaces/IERC20.sol'; // <= FOUND
9:
10: import { SafeTokenTransferFrom } from '../../../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
11:
12:
13:
14:
15:
16:
17:
18:
19: contract TokenManagerLiquidityPool is TokenManagerAddressStorage {
20:
21: uint256 internal constant LIQUIDITY_POOL_SLOT = 0x8e02741a3381812d092c5689c9fc701c5185c1742fdf7954c4c4472be4cc4807;
22:
23:
24:
25:
26:
27:
28: constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {}
29:
30: function implementationType() external pure returns (uint256) {
31: return 2;
32: }
33:
34:
3:
4:
5: pragma solidity ^0.8.0;
6:
7: import { FixedProxy } from '../../gmp-sdk/upgradable/FixedProxy.sol'; // <= FOUND
8: import { IStandardizedToken } from '../interfaces/IStandardizedToken.sol'; // <= FOUND
9: import { IStandardizedTokenProxy } from '../interfaces/IStandardizedTokenProxy.sol'; // <= FOUND
10:
11:
12:
13:
14:
15: contract StandardizedTokenProxy is FixedProxy, IStandardizedTokenProxy {
16: bytes32 private constant CONTRACT_ID = keccak256('standardized-token');
17:
18:
19:
20:
21:
22:
23: constructor(address implementationAddress, bytes memory params) FixedProxy(implementationAddress) {
24: if (IStandardizedToken(implementationAddress).contractId() != CONTRACT_ID) revert InvalidImplementation();
25:
26: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IStandardizedToken.setup.selector, params));
27: if (!success) revert SetupFailed();
28: }
29:
30:
31:
32:
33: function contractId() external pure returns (bytes32) {
2
Findings are labeled with ' <= FOUND'
Click to show findings
37: contract InterchainTokenService is
38: IInterchainTokenService,
39: AxelarExecutable,
40: Upgradable,
41: Operatable,
42: ExpressCallHandler,
43: Pausable,
44: Multicall
45: {
46: using StringToBytes32 for string;
47: using Bytes32ToString for bytes32;
48: using AddressBytesUtils for bytes;
49: using AddressBytesUtils for address;
50:
51: address internal immutable implementationLockUnlock;
52: address internal immutable implementationMintBurn;
53: address internal immutable implementationLiquidityPool;
54: IAxelarGasService public immutable gasService;
55: IRemoteAddressValidator public immutable remoteAddressValidator;
56: address public immutable tokenManagerDeployer;
57: address public immutable standardizedTokenDeployer;
58: Create3Deployer internal immutable deployer;
59: bytes32 internal immutable chainNameHash;
60: bytes32 internal immutable chainName;
61:
62: bytes32 internal constant PREFIX_CUSTOM_TOKEN_ID = keccak256('its-custom-token-id');
63: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_ID = keccak256('its-standardized-token-id');
64: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_SALT = keccak256('its-standardized-token-salt');
65:
66: uint256 private constant SELECTOR_SEND_TOKEN = 1;
67: uint256 private constant SELECTOR_SEND_TOKEN_WITH_DATA = 2;
68: uint256 private constant SELECTOR_DEPLOY_TOKEN_MANAGER = 3;
69: uint256 private constant SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN = 4;
70:
71: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service');
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83: constructor( // <= FOUND
84: address tokenManagerDeployer_,
85: address standardizedTokenDeployer_,
86: address gateway_,
87: address gasService_,
88: address remoteAddressValidator_,
89: address[] memory tokenManagerImplementations,
90: string memory chainName_
91: ) AxelarExecutable(gateway_) {
92: if (
93: remoteAddressValidator_ == address(0) ||
94: gasService_ == address(0) ||
95: tokenManagerDeployer_ == address(0) ||
96: standardizedTokenDeployer_ == address(0)
97: ) revert ZeroAddress();
98: remoteAddressValidator = IRemoteAddressValidator(remoteAddressValidator_);
99: gasService = IAxelarGasService(gasService_);
100: tokenManagerDeployer = tokenManagerDeployer_;
101: standardizedTokenDeployer = standardizedTokenDeployer_;
102: deployer = ITokenManagerDeployer(tokenManagerDeployer_).deployer();
103:
104: if (tokenManagerImplementations.length != uint256(type(TokenManagerType).max) + 1) revert LengthMismatch();
105:
106: implementationLockUnlock = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.LOCK_UNLOCK);
107: implementationMintBurn = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.MINT_BURN);
12: contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable {
13: using AddressToString for address;
14:
15: mapping(string => bytes32) public remoteAddressHashes;
16: mapping(string => string) public remoteAddresses;
17: address public immutable interchainTokenServiceAddress;
18: bytes32 public immutable interchainTokenServiceAddressHash;
19: mapping(string => bool) public supportedByGateway;
20:
21: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator');
22:
23:
24:
25:
26:
27: constructor(address _interchainTokenServiceAddress) { // <= FOUND
28: if (_interchainTokenServiceAddress == address(0)) revert ZeroAddress();
29: interchainTokenServiceAddress = _interchainTokenServiceAddress;
30: interchainTokenServiceAddressHash = keccak256(bytes(_lowerCase(interchainTokenServiceAddress.toString())));
31: }
32:
33:
34:
35:
36: function contractId() external pure returns (bytes32) {
37: return CONTRACT_ID;
38: }
39:
40: function _setup(bytes calldata params) internal override {
41: (string[] memory trustedChainNames, string[] memory trustedAddresses) = abi.decode(params, (string[], string[]));
42: uint256 length = trustedChainNames.length;
43: if (length != trustedAddresses.length) revert LengthMismatch();
44: for (uint256 i; i < length; ++i) {
45: addTrustedAddress(trustedChainNames[i], trustedAddresses[i]);
46: }
47: }
48:
49:
50:
51:
4
Remove the return statement once ensuring it is safe to do so
Findings are labeled with ' <= FOUND'
Click to show findings
223: function getImplementation(uint256 tokenManagerType) external view returns (address tokenManagerAddress) {
224:
225:
226: if (TokenManagerType(tokenManagerType) == TokenManagerType.LOCK_UNLOCK) {
227: return implementationLockUnlock; // <= FOUND
228: } else if (TokenManagerType(tokenManagerType) == TokenManagerType.MINT_BURN) {
229: return implementationMintBurn; // <= FOUND
230: } else if (TokenManagerType(tokenManagerType) == TokenManagerType.LIQUIDITY_POOL) {
231: return implementationLiquidityPool; // <= FOUND
232: }
233: }
827: function _getStandardizedTokenSalt(bytes32 tokenId) internal pure returns (bytes32 salt) {
828: return keccak256(abi.encode(PREFIX_STANDARDIZED_TOKEN_SALT, tokenId)); // <= FOUND
829: }
8
Rather than redefining state variable constant, consider utilising a library to store all constants as this will prevent data redundancy
Findings are labeled with ' <= FOUND'
Click to show findings
71: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service'); // <= FOUND
12: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator'); // <= FOUND
27: bytes32 private constant CONTRACT_ID = keccak256('standardized-token'); // <= FOUND
14: bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; // <= FOUND
16: bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0; // <= FOUND
22: uint256 internal constant TOKEN_ADDRESS_SLOT = 0xc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42ba; // <= FOUND
15: address internal immutable implementationAddress; // <= FOUND
13: address private immutable implementationAddress; // <= FOUND
6
Using a single struct mapping in place of multiple defined mappings in a Solidity contract can lead to improved code organization, better readability, and easier maintainability. By consolidating related data into a single struct, developers can create a more cohesive data structure that logically groups together relevant pieces of information, thus reducing redundancy and clutter. This approach simplifies the codebase, making it easier to understand, navigate, and modify. Additionally, it can result in more efficient gas usage when accessing or updating multiple related data points simultaneously.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L20-L20
12: contract MultisigBase is IMultisigBase {
13:
14:
15:
16:
17: Signers public signers;
18: uint256 public signerEpoch;
19:
20: mapping(uint256 => mapping(bytes32 => Voting)) public votingPerTopic; // <= FOUND
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
22: contract InterchainProposalExecutor is IInterchainProposalExecutor, AxelarExecutable, Ownable {
23:
24: mapping(string => mapping(address => bool)) public whitelistedCallers; // <= FOUND
25:
26:
27: mapping(string => mapping(address => bool)) public whitelistedSenders; // <= FOUND
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
12: contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable {
13: using AddressToString for address;
14:
15: mapping(string => bytes32) public remoteAddressHashes; // <= FOUND
16: mapping(string => string) public remoteAddresses; // <= FOUND
17: address public immutable interchainTokenServiceAddress;
18: bytes32 public immutable interchainTokenServiceAddressHash;
19: mapping(string => bool) public supportedByGateway; // <= FOUND
20:
21: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator');
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
21
Consider using abi.encode as this pads data to 32 byte segments
Findings are labeled with ' <= FOUND'
Click to show findings
68: function executeProposal(
69: address target,
70: bytes calldata callData,
71: uint256 nativeValue
72: ) external payable {
73: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
74:
75: _finalizeTimeLock(proposalHash);
76: _call(target, callData, nativeValue);
77:
78: emit ProposalExecuted(proposalHash, target, callData, nativeValue, block.timestamp);
79: }
143: function _getProposalHash(
144: address target,
145: bytes memory callData,
146: uint256 nativeValue
147: ) internal pure returns (bytes32) {
148: return keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
149: }
48: function executeMultisigProposal(
49: address target,
50: bytes calldata callData,
51: uint256 nativeValue
52: ) external payable onlySigners {
53: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
54:
55: if (!multisigApprovals[proposalHash]) revert NotApproved();
56:
57: multisigApprovals[proposalHash] = false;
58:
59: _call(target, callData, nativeValue);
60:
61: emit MultisigExecuted(proposalHash, target, callData, nativeValue);
62: }
72: function _processCommand(
73: uint256 commandId,
74: address target,
75: bytes memory callData,
76: uint256 nativeValue,
77: uint256 eta
78: ) internal override {
79: if (commandId > uint256(type(ServiceGovernanceCommand).max)) {
80: revert InvalidCommand();
81: }
82:
83: ServiceGovernanceCommand command = ServiceGovernanceCommand(commandId);
84: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
85:
86: if (command == ServiceGovernanceCommand.ScheduleTimeLockProposal) {
87: eta = _scheduleTimeLock(proposalHash, eta);
88:
89: emit ProposalScheduled(proposalHash, target, callData, nativeValue, eta);
90: return;
91: } else if (command == ServiceGovernanceCommand.CancelTimeLockProposal) {
92: _cancelTimeLock(proposalHash);
93:
94: emit ProposalCancelled(proposalHash, target, callData, nativeValue, eta);
95: return;
96: } else if (command == ServiceGovernanceCommand.ApproveMultisigProposal) {
97: multisigApprovals[proposalHash] = true;
98:
99: emit MultisigApproved(proposalHash, target, callData, nativeValue);
100: return;
101: } else if (command == ServiceGovernanceCommand.CancelMultisigApproval) {
102: multisigApprovals[proposalHash] = false;
103:
104: emit MultisigCancelled(proposalHash, target, callData, nativeValue);
105: return;
106: }
107: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L92-L93
92: function _getTimeLockEta(bytes32 hash) internal view returns (uint256 eta) {
93: bytes32 key = keccak256(abi.encodePacked(PREFIX_TIME_LOCK, hash)); // <= FOUND
94:
95: assembly {
96: eta := sload(key)
97: }
98: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L103-L104
103: function _setTimeLockEta(bytes32 hash, uint256 eta) private {
104: bytes32 key = keccak256(abi.encodePacked(PREFIX_TIME_LOCK, hash)); // <= FOUND
105:
106: assembly {
107: sstore(key, eta)
108: }
109: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L322-L349
322: function execute(bytes calldata input) external override {
323: (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));
324:
325: bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data)); // <= FOUND
326:
327:
328: bool allowOperatorshipTransfer = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);
329:
330: uint256 chainId;
331: bytes32[] memory commandIds;
332: string[] memory commands;
333: bytes[] memory params;
334:
335: (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));
336:
337: if (chainId != block.chainid) revert InvalidChainId();
338:
339: uint256 commandsLength = commandIds.length;
340:
341: if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
342:
343: for (uint256 i; i < commandsLength; ++i) {
344: bytes32 commandId = commandIds[i];
345:
346: if (isCommandExecuted(commandId)) continue;
347:
348: bytes4 commandSelector;
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i])); // <= FOUND
350:
351: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
352: commandSelector = AxelarGateway.deployToken.selector;
353: } else if (commandHash == SELECTOR_MINT_TOKEN) {
354: commandSelector = AxelarGateway.mintToken.selector;
355: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
356: commandSelector = AxelarGateway.approveContractCall.selector;
357: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
358: commandSelector = AxelarGateway.approveContractCallWithMint.selector;
359: } else if (commandHash == SELECTOR_BURN_TOKEN) {
360: commandSelector = AxelarGateway.burnToken.selector;
361: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
362: if (!allowOperatorshipTransfer) continue;
363:
364: allowOperatorshipTransfer = false;
365: commandSelector = AxelarGateway.transferOperatorship.selector;
366: } else {
367: continue;
368: }
369:
370:
371: _setCommandExecuted(commandId, true);
372:
373: (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId));
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L384-L395
384: function deployToken(bytes calldata params, bytes32) external onlySelf {
385: (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode(
386: params,
387: (string, string, uint8, uint256, address, uint256)
388: );
389:
390:
391: if (tokenAddresses(symbol) != address(0)) revert TokenAlreadyExists(symbol);
392:
393: if (tokenAddress == address(0)) {
394:
395: bytes32 salt = keccak256(abi.encodePacked(symbol)); // <= FOUND
396:
397: (bool success, bytes memory data) = TOKEN_DEPLOYER_IMPLEMENTATION.delegatecall(
398: abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt)
399: );
400:
401: if (!success) revert TokenDeployFailed(symbol);
402:
403: tokenAddress = abi.decode(data, (address));
404:
405: _setTokenType(symbol, TokenType.InternalBurnableFrom);
406: } else {
407:
408: if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);
409:
410:
411: _setTokenType(symbol, TokenType.External);
412: }
413:
414: _setTokenAddress(symbol, tokenAddress);
415: _setTokenMintLimit(symbol, mintLimit);
416:
417: emit TokenDeployed(symbol, tokenAddress);
418: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L426-L434
426: function burnToken(bytes calldata params, bytes32) external onlySelf {
427: (string memory symbol, bytes32 salt) = abi.decode(params, (string, bytes32));
428:
429: address tokenAddress = tokenAddresses(symbol);
430:
431: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
432:
433: if (_getTokenType(symbol) == TokenType.External) {
434: address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode))); // <= FOUND
435:
436: if (_hasCode(depositHandlerAddress)) return;
437:
438: DepositHandler depositHandler = new DepositHandler{ salt: salt }();
439:
440: (bool success, bytes memory returnData) = depositHandler.execute(
441: tokenAddress,
442: abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler)))
443: );
444:
445: if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol);
446:
447:
448: depositHandler.destroy(address(this));
449: } else {
450: IBurnableMintableCappedERC20(tokenAddress).burn(salt);
451: }
452: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L555-L556
555: function _getTokenMintLimitKey(string memory symbol) internal pure returns (bytes32) {
556: return keccak256(abi.encodePacked(PREFIX_TOKEN_MINT_LIMIT, symbol)); // <= FOUND
557: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L564-L565
564: function _getTokenTypeKey(string memory symbol) internal pure returns (bytes32) {
565: return keccak256(abi.encodePacked(PREFIX_TOKEN_TYPE, symbol)); // <= FOUND
566: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L568-L569
568: function _getTokenAddressKey(string memory symbol) internal pure returns (bytes32) {
569: return keccak256(abi.encodePacked(PREFIX_TOKEN_ADDRESS, symbol)); // <= FOUND
570: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L572-L573
572: function _getIsCommandExecutedKey(bytes32 commandId) internal pure returns (bytes32) {
573: return keccak256(abi.encodePacked(PREFIX_COMMAND_EXECUTED, commandId)); // <= FOUND
574: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L614-L615
614: function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) {
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash))))); // <= FOUND
616: }
58: function deployedAddress(
59: bytes calldata bytecode,
60: address sender,
61: bytes32 salt
62: ) external view returns (address deployedAddress_) {
63: bytes32 newSalt = keccak256(abi.encode(sender, salt)); // <= FOUND
64: deployedAddress_ = address(
65: uint160(
66: uint256(
67: keccak256( // <= FOUND
68: abi.encodePacked( // <= FOUND
69: hex'ff',
70: address(this),
71: newSalt,
72: keccak256(bytecode) // <= FOUND
73: )
74: )
75: )
76: )
77: );
78: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L71-L74
71: function deployedAddress(address sender, bytes32 salt) internal pure returns (address deployed) {
72: address deployer = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', sender, salt, DEPLOYER_BYTECODE_HASH))))); // <= FOUND
73:
74: deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01'))))); // <= FOUND
75: }
11
Putting constants on the left side of a comparison operator like ==
or <
is a best practice known as "Yoda conditions", which can help prevent accidental assignment instead of comparison. In some programming languages, if a variable is mistakenly put on the left with a single =
instead of ==
, it assigns the constant's value to the variable without any compiler error. However, doing this with the constant on the left would generate an error, as constants cannot be assigned values. Although Solidity's static typing system prevents accidental assignments within conditionals, adopting this practice enhances code readability and consistency, especially when developers are working across multiple languages that support this convention.
Findings are labeled with ' <= FOUND'
Click to show findings
80: if (setupParams.length != 0) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L315-L315
315: if (newOperatorsData.length != 0) // <= FOUND
57: if (params.length != 0) // <= FOUND
135: if (bytes(remoteAddress).length == 0) // <= FOUND
68: if (operatorBytes.length == 0) // <= FOUND
91: if (interchainCall.gas > 0) // <= FOUND
161: if (result.length > 0) // <= FOUND
60: if (params.length > 0) // <= FOUND
714: if (gasValue > 0) // <= FOUND
64: if (mintAmount > 0) // <= FOUND
511: if (metadata.length < 4) // <= FOUND
30
Such instances can be replaced with unnamed returns
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L92-L92
92: function _getTimeLockEta(bytes32 hash) internal view returns (uint256 eta) // <= FOUND
22: function implementation() public view virtual returns (address implementation_) // <= FOUND
39: function implementation() public view returns (address implementation_) // <= FOUND
37: function implementation() public view override(BaseProxy, IProxy) returns (address implementation_) // <= FOUND
44: function implementation() public view returns (address impl) // <= FOUND
202: function getCanonicalTokenId(address tokenAddress) public view returns (bytes32 tokenId) // <= FOUND
213: function getCustomTokenId(address sender, bytes32 salt) public pure returns (bytes32 tokenId) // <= FOUND
223: function getImplementation(uint256 tokenManagerType) external view returns (address tokenManagerAddress) // <= FOUND
275: function getFlowLimit(bytes32 tokenId) external view returns (uint256 flowLimit) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L24-L24
24: function getFlowLimit() public view returns (uint256 flowLimit) // <= FOUND
285: function getFlowOutAmount(bytes32 tokenId) external view returns (uint256 flowOutAmount) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L63-L63
63: function getFlowOutAmount() external view returns (uint256 flowOutAmount) // <= FOUND
295: function getFlowInAmount(bytes32 tokenId) external view returns (uint256 flowInAmount) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L75-L75
75: function getFlowInAmount() external view returns (uint256 flowInAmount) // <= FOUND
309: function registerCanonicalToken(address tokenAddress) external payable notPaused returns (bytes32 tokenId) // <= FOUND
343: function deployCustomTokenManager( // <= FOUND
344: bytes32 salt, // <= FOUND
345: TokenManagerType tokenManagerType, // <= FOUND
346: bytes memory params // <= FOUND
347: ) public payable notPaused returns (bytes32 tokenId) // <= FOUND
365: function deployRemoteCustomTokenManager( // <= FOUND
366: bytes32 salt, // <= FOUND
367: string calldata destinationChain, // <= FOUND
368: TokenManagerType tokenManagerType, // <= FOUND
369: bytes calldata params, // <= FOUND
370: uint256 gasValue // <= FOUND
371: ) external payable notPaused returns (bytes32 tokenId) // <= FOUND
827: function _getStandardizedTokenSalt(bytes32 tokenId) internal pure returns (bytes32 salt) // <= FOUND
204: function _getTokenId() internal view returns (bytes32 tokenId) // <= FOUND
57: function liquidityPool() public view returns (address liquidityPool_) // <= FOUND
19
Make found instants CAPITAL_CASE
Findings are labeled with ' <= FOUND'
Click to show findings
23: bytes32 public immutable governanceChainHash; // <= FOUND
24: bytes32 public immutable governanceAddressHash; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L15-L15
15: uint256 internal immutable _minimumTimeLockDelay; // <= FOUND
17: address public immutable implementation; // <= FOUND
51: address internal immutable implementationLockUnlock; // <= FOUND
52: address internal immutable implementationMintBurn; // <= FOUND
53: address internal immutable implementationLiquidityPool; // <= FOUND
56: address public immutable tokenManagerDeployer; // <= FOUND
57: address public immutable standardizedTokenDeployer; // <= FOUND
59: bytes32 internal immutable chainNameHash; // <= FOUND
60: bytes32 internal immutable chainName; // <= FOUND
15: uint256 public immutable implementationType; // <= FOUND
17: address public immutable interchainTokenServiceAddress; // <= FOUND
18: bytes32 public immutable interchainTokenServiceAddressHash; // <= FOUND
17: address public immutable implementationMintBurnAddress; // <= FOUND
18: address public immutable implementationLockUnlockAddress; // <= FOUND
15: address internal immutable implementationAddress; // <= FOUND
13: address private immutable implementationAddress; // <= FOUND
16: bytes32 public immutable tokenId; // <= FOUND
6
In Solidity version 0.8.18 and beyond mapping parameters can be named. This makes the purpose and function of a given mapping far clearer which in turn improves readability.
Findings are labeled with ' <= FOUND'
Click to show findings
22: mapping(bytes32 => bool) public multisigApprovals; // <= FOUND
24: mapping(string => mapping(address => bool)) public whitelistedCallers; // <= FOUND
27: mapping(string => mapping(address => bool)) public whitelistedSenders; // <= FOUND
19: mapping(string => bool) public supportedByGateway; // <= FOUND
16: mapping(string => string) public remoteAddresses; // <= FOUND
15: mapping(string => bytes32) public remoteAddressHashes; // <= FOUND
40
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L13-L13
12: contract TimeLock is ITimeLock {
13: bytes32 internal constant PREFIX_TIME_LOCK = keccak256('time-lock'); // <= FOUND
14:
15: uint256 internal immutable _minimumTimeLockDelay;
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L35-L57
17: contract AxelarGateway is IAxelarGateway, IGovernable, AdminMultisigBase {
18: using SafeTokenCall for IERC20;
19: using SafeTokenTransfer for IERC20;
20: using SafeTokenTransferFrom for IERC20;
21:
22: error InvalidImplementation();
23:
24: enum TokenType {
25: InternalBurnable,
26: InternalBurnableFrom,
27: External
28: }
29:
30:
31:
32:
33:
34:
35: bytes32 internal constant KEY_IMPLEMENTATION = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc); // <= FOUND
36:
37:
38: bytes32 internal constant KEY_GOVERNANCE = bytes32(0xabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909); // <= FOUND
39:
40:
41: bytes32 internal constant KEY_MINT_LIMITER = bytes32(0x627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92); // <= FOUND
42:
43:
44: bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed'); // <= FOUND
45: bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address'); // <= FOUND
46: bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type'); // <= FOUND
47: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved'); // <= FOUND
48: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint'); // <= FOUND
49: bytes32 internal constant PREFIX_TOKEN_MINT_LIMIT = keccak256('token-mint-limit'); // <= FOUND
50: bytes32 internal constant PREFIX_TOKEN_MINT_AMOUNT = keccak256('token-mint-amount'); // <= FOUND
51:
52: bytes32 internal constant SELECTOR_BURN_TOKEN = keccak256('burnToken'); // <= FOUND
53: bytes32 internal constant SELECTOR_DEPLOY_TOKEN = keccak256('deployToken'); // <= FOUND
54: bytes32 internal constant SELECTOR_MINT_TOKEN = keccak256('mintToken'); // <= FOUND
55: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL = keccak256('approveContractCall'); // <= FOUND
56: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT = keccak256('approveContractCallWithMint'); // <= FOUND
57: bytes32 internal constant SELECTOR_TRANSFER_OPERATORSHIP = keccak256('transferOperatorship'); // <= FOUND
58:
59:
60: address internal immutable AUTH_MODULE;
61:
62: address internal immutable TOKEN_DEPLOYER_IMPLEMENTATION;
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
17: contract FinalProxy is Proxy, IFinalProxy {
18: bytes32 internal constant FINAL_IMPLEMENTATION_SALT = keccak256('final-implementation'); // <= FOUND
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
37: contract InterchainTokenService is
38: IInterchainTokenService,
39: AxelarExecutable,
40: Upgradable,
41: Operatable,
42: ExpressCallHandler,
43: Pausable,
44: Multicall
45: {
46: using StringToBytes32 for string;
47: using Bytes32ToString for bytes32;
48: using AddressBytesUtils for bytes;
49: using AddressBytesUtils for address;
50:
51: address internal immutable implementationLockUnlock;
52: address internal immutable implementationMintBurn;
53: address internal immutable implementationLiquidityPool;
54: IAxelarGasService public immutable gasService;
55: IRemoteAddressValidator public immutable remoteAddressValidator;
56: address public immutable tokenManagerDeployer;
57: address public immutable standardizedTokenDeployer;
58: Create3Deployer internal immutable deployer;
59: bytes32 internal immutable chainNameHash;
60: bytes32 internal immutable chainName;
61:
62: bytes32 internal constant PREFIX_CUSTOM_TOKEN_ID = keccak256('its-custom-token-id'); // <= FOUND
63: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_ID = keccak256('its-standardized-token-id'); // <= FOUND
64: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_SALT = keccak256('its-standardized-token-salt'); // <= FOUND
65:
66: uint256 private constant SELECTOR_SEND_TOKEN = 1; // <= FOUND
67: uint256 private constant SELECTOR_SEND_TOKEN_WITH_DATA = 2; // <= FOUND
68: uint256 private constant SELECTOR_DEPLOY_TOKEN_MANAGER = 3; // <= FOUND
69: uint256 private constant SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN = 4; // <= FOUND
70:
71: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service'); // <= FOUND
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
11: contract InterchainTokenServiceProxy is FinalProxy {
12: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service'); // <= FOUND
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26: }
11: contract RemoteAddressValidatorProxy is Proxy {
12: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator'); // <= FOUND
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27: }
13: contract StandardizedTokenProxy is FixedProxy, IStandardizedTokenProxy {
14: bytes32 private constant CONTRACT_ID = keccak256('standardized-token'); // <= FOUND
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27: }
12: contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable {
13: using AddressToString for address;
14:
15: mapping(string => bytes32) public remoteAddressHashes;
16: mapping(string => string) public remoteAddresses;
17: address public immutable interchainTokenServiceAddress;
18: bytes32 public immutable interchainTokenServiceAddressHash;
19: mapping(string => bool) public supportedByGateway;
20:
21: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator'); // <= FOUND
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
17: contract TokenManagerLiquidityPool is TokenManagerAddressStorage {
18:
19: uint256 internal constant LIQUIDITY_POOL_SLOT = 0x8e02741a3381812d092c5689c9fc701c5185c1742fdf7954c4c4472be4cc4807; // <= FOUND
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L15-L15
13: contract Distributable is IDistributable {
14:
15: uint256 internal constant DISTRIBUTOR_SLOT = 0x71c5a35e45a25c49e8f747acd4bcb869814b3d104c492d2554f4c46e12371f56; // <= FOUND
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
12: contract ExpressCallHandler is IExpressCallHandler {
13:
14: uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN = 0x67c7b41c1cb0375e36084c4ec399d005168e83425fa471b9224f6115af865619; // <= FOUND
15:
16: uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA = 0x3e607cc12a253b1d9f677a03d298ad869a90a8ba4bd0fb5739e7d79db7cdeaad; // <= FOUND
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L14-L18
12: contract FlowLimit is IFlowLimit {
13:
14: uint256 internal constant FLOW_LIMIT_SLOT = 0x201b7a0b7c19aaddc4ce9579b7df8d2db123805861bc7763627f13e04d8af42f; // <= FOUND
15: uint256 internal constant PREFIX_FLOW_OUT_AMOUNT = uint256(keccak256('prefix-flow-out-amount')); // <= FOUND
16: uint256 internal constant PREFIX_FLOW_IN_AMOUNT = uint256(keccak256('prefix-flow-in-amount')); // <= FOUND
17:
18: uint256 internal constant EPOCH_TIME = 6 hours; // <= FOUND
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L15-L15
13: contract Operatable is IOperatable {
14:
15: uint256 internal constant OPERATOR_SLOT = 0xf23ec0bb4210edd5cba85afd05127efcd2fc6a781bfed49188da1081670b22d7; // <= FOUND
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L14-L14
12: contract Pausable is IPausable {
13:
14: uint256 internal constant PAUSE_SLOT = 0xee35723ac350a69d2a92d3703f17439cbaadf2f093a21ba5bf5f1a53eb2a14d8; // <= FOUND
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35: }
13
Findings are labeled with ' <= FOUND'
Click to show findings
155: function _executeWithToken( // <= FOUND
156: string calldata,
157: string calldata,
158: bytes calldata,
159: string calldata,
160: uint256
161: ) internal pure override {
162: revert TokenNotSupported();
163: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L223-L223
223: function admins(uint256) external pure override returns (address[] memory) { // <= FOUND
224: return new address[](0);
225: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L208-L208
208: function allTokensFrozen() external pure override returns (bool) { // <= FOUND
209: return false;
210: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L237-L237
237: function tokenFrozen(string memory) external pure override returns (bool) { // <= FOUND
238: return false;
239: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L420-L420
420: function mintToken(bytes calldata params, bytes32) external onlySelf { // <= FOUND
421: (string memory symbol, address account, uint256 amount) = abi.decode(params, (string, address, uint256));
422:
423: _mintToken(symbol, account, amount);
424: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L494-L494
494: function transferOperatorship(bytes calldata newOperatorsData, bytes32) external onlySelf { // <= FOUND
495: IAxelarAuth(AUTH_MODULE).transferOperatorship(newOperatorsData);
496:
497: emit OperatorshipTransferred(newOperatorsData);
498: }
126: function _beforeProposalExecuted( // <= FOUND
127: string calldata sourceChain,
128: string calldata sourceAddress,
129: bytes calldata payload
130: ) internal virtual {
131:
132: }
142: function _onProposalExecuted( // <= FOUND
143: string calldata,
144: string calldata,
145: address,
146: bytes calldata payload
147: ) internal virtual {
148:
149: }
178: function _onTargetExecuted(InterchainCalls.Call memory call, bytes memory result) internal virtual { // <= FOUND
179:
180: }
156: function _onTargetExecutionFailed( // <= FOUND
157: InterchainCalls.Call memory,
158: bytes memory result
159: ) internal virtual {
160:
161: if (result.length > 0) {
162:
163: assembly {
164: revert(add(32, result), mload(result))
165: }
166: } else {
167:
168: revert ProposalExecuteFailed();
169: }
170: }
32: function setup(bytes calldata params) external {} // <= FOUND
31: function setup(bytes calldata setupParams) external {} // <= FOUND
87: function _setup(bytes calldata data) internal virtual {} // <= FOUND
30
Allowing a function in Solidity to return the default address (address(0)) can be problematic as it can represent uninitialized or invalid addresses. If such an address is utilized in transfer operations or other sensitive actions, it could lead to loss of funds or unpredicted behavior. It's prudent to include checks in your functions to prevent the return of the zero address, enhancing contract security.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L182-L182
182: function authModule() public view override returns (address) {
183: return AUTH_MODULE;
184: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L186-L186
186: function governance() public view override returns (address) {
187: return getAddress(KEY_GOVERNANCE);
188: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L190-L190
190: function mintLimiter() public view override returns (address) {
191: return getAddress(KEY_MINT_LIMITER);
192: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L194-L194
194: function tokenDeployer() public view returns (address) {
195: return TOKEN_DEPLOYER_IMPLEMENTATION;
196: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L227-L227
227: function implementation() public view override returns (address) {
228: return getAddress(KEY_IMPLEMENTATION);
229: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L231-L231
231: function tokenAddresses(string memory symbol) public view override returns (address) {
232: return getAddress(_getTokenAddressKey(symbol));
233: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L614-L614
614: function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) {
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash)))));
616: }
24: function deploy(bytes memory bytecode, bytes32 salt) external returns (address deployedAddress_) {
25: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt)));
26: }
58: function deployedAddress(
59: bytes calldata bytecode,
60: address sender,
61: bytes32 salt
62: ) external view returns (address deployedAddress_) {
63: bytes32 newSalt = keccak256(abi.encode(sender, salt));
64: deployedAddress_ = address(
65: uint160(
66: uint256(
67: keccak256(
68: abi.encodePacked(
69: hex'ff',
70: address(this),
71: newSalt,
72: keccak256(bytecode)
73: )
74: )
75: )
76: )
77: );
78: }
29: function deploy(bytes calldata bytecode, bytes32 salt) external returns (address deployedAddress_) {
30: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt));
31: deployedAddress_ = Create3.deploy(deploySalt, bytecode);
32:
33: emit Deployed(keccak256(bytecode), salt, deployedAddress_);
34: }
67: function deployedAddress(address sender, bytes32 salt) external view returns (address) {
68: bytes32 deploySalt = keccak256(abi.encode(sender, salt));
69: return Create3.deployedAddress(address(this), deploySalt);
70: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L71-L71
71: function deployedAddress(address sender, bytes32 salt) internal pure returns (address deployed) {
72: address deployer = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', sender, salt, DEPLOYER_BYTECODE_HASH)))));
73:
74: deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01')))));
75: }
22: function implementation() public view virtual returns (address implementation_) {
23: assembly {
24: implementation_ := sload(_IMPLEMENTATION_SLOT)
25: }
26: }
39: function implementation() public view returns (address implementation_) {
40: assembly {
41: implementation_ := sload(_IMPLEMENTATION_SLOT)
42: }
43: }
37: function implementation() public view override(BaseProxy, IProxy) returns (address implementation_) {
38: implementation_ = _finalImplementation();
39: if (implementation_ == address(0)) {
40: implementation_ = super.implementation();
41: }
42: }
57: function _finalImplementation() internal view virtual returns (address implementation_) {
58:
59:
60:
61: implementation_ = Create3.deployedAddress(address(this), FINAL_IMPLEMENTATION_SALT);
62:
63: if (implementation_.code.length == 0) implementation_ = address(0);
64: }
161: function getTokenManagerAddress(bytes32 tokenId) public view returns (address tokenManagerAddress) {
162: tokenManagerAddress = deployer.deployedAddress(address(this), tokenId);
163: }
180: function getTokenAddress(bytes32 tokenId) external view returns (address tokenAddress) {
181: address tokenManagerAddress = getValidTokenManagerAddress(tokenId);
182: tokenAddress = ITokenManager(tokenManagerAddress).tokenAddress();
183: }
191: function getStandardizedTokenAddress(bytes32 tokenId) public view returns (address tokenAddress) {
192: tokenId = _getStandardizedTokenSalt(tokenId);
193: tokenAddress = deployer.deployedAddress(address(this), tokenId);
194: }
223: function getImplementation(uint256 tokenManagerType) external view returns (address tokenManagerAddress) {
224:
225:
226: if (TokenManagerType(tokenManagerType) == TokenManagerType.LOCK_UNLOCK) {
227: return implementationLockUnlock;
228: } else if (TokenManagerType(tokenManagerType) == TokenManagerType.MINT_BURN) {
229: return implementationMintBurn;
230: } else if (TokenManagerType(tokenManagerType) == TokenManagerType.LIQUIDITY_POOL) {
231: return implementationLiquidityPool;
232: }
233: }
44: function implementation() public view returns (address impl) {
45: impl = _getImplementation(interchainTokenServiceAddress, implementationType);
46: }
54: function _getImplementation(IInterchainTokenService interchainTokenServiceAddress_, uint256 implementationType_)
55: internal
56: view
57: returns (address impl)
58: {
59: impl = interchainTokenServiceAddress_.getImplementation(implementationType_);
60: }
28: function tokenAddress() public view override returns (address tokenAddress_) {
29: assembly {
30: tokenAddress_ := sload(TOKEN_ADDRESS_SLOT)
31: }
32: }
57: function liquidityPool() public view returns (address liquidityPool_) {
58: assembly {
59: liquidityPool_ := sload(LIQUIDITY_POOL_SLOT)
60: }
61: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L29-L29
29: function distributor() public view returns (address distr) {
30: assembly {
31: distr := sload(DISTRIBUTOR_SLOT)
32: }
33: }
148: function getExpressReceiveToken(
149: bytes32 tokenId,
150: address destinationAddress,
151: uint256 amount,
152: bytes32 commandId
153: ) public view returns (address expressCaller) {
154: uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId);
155: assembly {
156: expressCaller := sload(slot)
157: }
158: }
171: function getExpressReceiveTokenWithData(
172: bytes32 tokenId,
173: string memory sourceChain,
174: bytes memory sourceAddress,
175: address destinationAddress,
176: uint256 amount,
177: bytes calldata data,
178: bytes32 commandId
179: ) public view returns (address expressCaller) {
180: uint256 slot = _getExpressReceiveTokenWithDataSlot(
181: tokenId,
182: sourceChain,
183: sourceAddress,
184: destinationAddress,
185: amount,
186: data,
187: commandId
188: );
189: assembly {
190: expressCaller := sload(slot)
191: }
192: }
202: function _popExpressReceiveToken(
203: bytes32 tokenId,
204: address destinationAddress,
205: uint256 amount,
206: bytes32 commandId
207: ) internal returns (address expressCaller) {
208: uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId);
209: assembly {
210: expressCaller := sload(slot)
211: }
212: if (expressCaller != address(0)) {
213: assembly {
214: sstore(slot, 0)
215: }
216: emit ExpressExecutionFulfilled(tokenId, destinationAddress, amount, commandId, expressCaller);
217: }
218: }
231: function _popExpressReceiveTokenWithData(
232: bytes32 tokenId,
233: string memory sourceChain,
234: bytes memory sourceAddress,
235: address destinationAddress,
236: uint256 amount,
237: bytes memory data,
238: bytes32 commandId
239: ) internal returns (address expressCaller) {
240: uint256 slot = _getExpressReceiveTokenWithDataSlot(
241: tokenId,
242: sourceChain,
243: sourceAddress,
244: destinationAddress,
245: amount,
246: data,
247: commandId
248: );
249: assembly {
250: expressCaller := sload(slot)
251: }
252: if (expressCaller != address(0)) {
253: assembly {
254: sstore(slot, 0)
255: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L29-L29
29: function operator() public view returns (address operator_) {
30: assembly {
31: operator_ := sload(OPERATOR_SLOT)
32: }
33: }
33
Critical functions in Solidity contracts should follow a two-step procedure to enhance security, minimize human error, and ensure proper access control. By dividing sensitive operations into distinct phases, such as initiation and confirmation, developers can introduce a safeguard against unintended actions or unauthorized access.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L265-L265
265: function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external override onlyMintLimiter // <= FOUND
61: function setup(bytes calldata params) external override // <= FOUND
92: function setWhitelistedProposalCaller( // <= FOUND
93: string calldata sourceChain,
94: address sourceCaller,
95: bool whitelisted
96: ) external override onlyOwner
107: function setWhitelistedProposalSender( // <= FOUND
108: string calldata sourceChain,
109: address sourceSender,
110: bool whitelisted
111: ) external override onlyOwner
61: function setup(bytes calldata params) external // <= FOUND
78: function setup(bytes calldata data) external override onlyProxy // <= FOUND
31: function setup(bytes calldata setupParams) external // <= FOUND
534: function setFlowLimit(bytes32[] calldata tokenIds, uint256[] calldata flowLimits) external onlyOperator // <= FOUND
547: function setPaused(bool paused) external onlyOwner // <= FOUND
61: function setup(bytes calldata params) external override onlyProxy // <= FOUND
171: function setFlowLimit(uint256 flowLimit) external onlyOperator // <= FOUND
67: function setLiquidityPool(address newLiquidityPool) external onlyOperator // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L51-L51
51: function setDistributor(address distr) external onlyDistributor // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L51-L51
51: function setOperator(address operator_) external onlyOperator // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L103-L103
103: function _setTimeLockEta(bytes32 hash, uint256 eta) private // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L626-L626
626: function _setTokenMintLimit(string memory symbol, uint256 limit) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L632-L632
632: function _setTokenMintAmount(string memory symbol, uint256 amount) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L639-L639
639: function _setTokenType(string memory symbol, TokenType tokenType) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L643-L643
643: function _setTokenAddress(string memory symbol, address tokenAddress) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L647-L647
647: function _setCommandExecuted(bytes32 commandId, bool executed) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L651-L651
651: function _setContractCallApproved( // <= FOUND
652: bytes32 commandId,
653: string memory sourceChain,
654: string memory sourceAddress,
655: address contractAddress,
656: bytes32 payloadHash
657: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L661-L661
661: function _setContractCallApprovedWithMint( // <= FOUND
662: bytes32 commandId,
663: string memory sourceChain,
664: string memory sourceAddress,
665: address contractAddress,
666: bytes32 payloadHash,
667: string memory symbol,
668: uint256 amount
669: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L676-L676
676: function _setImplementation(address newImplementation) internal // <= FOUND
87: function _setup(bytes calldata data) internal virtual // <= FOUND
40: function _setup(bytes calldata params) internal override // <= FOUND
38: function _setTokenAddress(address tokenAddress_) internal // <= FOUND
47: function _setLiquidityPool(address liquidityPool_) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L39-L39
39: function _setDistributor(address distributor_) internal // <= FOUND
79: function _setExpressReceiveToken( // <= FOUND
80: bytes32 tokenId,
81: address destinationAddress,
82: uint256 amount,
83: bytes32 commandId,
84: address expressCaller
85: ) internal
110: function _setExpressReceiveTokenWithData( // <= FOUND
111: bytes32 tokenId,
112: string memory sourceChain,
113: bytes memory sourceAddress,
114: address destinationAddress,
115: uint256 amount,
116: bytes calldata data,
117: bytes32 commandId,
118: address expressCaller
119: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L34-L34
34: function _setFlowLimit(uint256 flowLimit) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L39-L39
39: function _setOperator(address operator_) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L41-L41
41: function _setPaused(bool paused) internal // <= FOUND
2
Magic numbers should be avoided in Solidity code to enhance readability, maintainability, and reduce the likelihood of errors. Magic numbers are hard-coded values with no clear meaning or context, which can create confusion and make the code harder to understand for developers. Using well-defined constants or variables with descriptive names instead of magic numbers not only clarifies the purpose and significance of the value but also simplifies code updates and modifications.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L203-L203
202: function tokenMintAmount(string memory symbol) public view override returns (uint256) {
203: return getUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours)); // <= FOUND
204: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L636-L636
632: function _setTokenMintAmount(string memory symbol, uint256 amount) internal {
633: uint256 limit = tokenMintLimit(symbol);
634: if (limit > 0 && amount > limit) revert ExceedMintLimit(symbol);
635:
636: _setUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours), amount); // <= FOUND
637: }
6
Findings are labeled with ' <= FOUND'
Click to show findings
15: contract Proxy is BaseProxy // <= FOUND
11: contract InterchainTokenServiceProxy is FinalProxy // <= FOUND
11: contract RemoteAddressValidatorProxy is Proxy // <= FOUND
13: contract StandardizedTokenProxy is FixedProxy, IStandardizedTokenProxy // <= FOUND
7: contract StandardizedTokenLockUnlock is StandardizedToken // <= FOUND
7: contract StandardizedTokenMintBurn is StandardizedToken // <= FOUND
4
Assigning such addresses during construction is preferred as this allows flexibility when deploying to other EVM chains
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L504-L508
504: function _hasCode(address addr) internal view returns (bool) { // <= FOUND
505: bytes32 codehash = addr.codehash;
506:
507:
508: return codehash != bytes32(0) && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // <= FOUND
509: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L614-L615
614: function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) { // <= FOUND
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash))))); // <= FOUND
616: }
21
It's crucial to leverage the right features for the appropriate contexts in Solidity, despite the compiler's ability to correct common developer mistakes. Both constant
and immutable
variables have distinct uses. Constant
variables are best suited for hard-coded, literal values within your contract, where the value doesn't need to be computed or modified.
On the other hand, immutable
variables are ideal for situations where the value might be the result of an expression or received from a constructor. While both serve to define unchanging variables, they function differently and their proper utilization contributes to clearer, more efficient code. Remember, even if the compiler can correct certain mistakes, best practices dictate using the correct feature for the task at hand.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L13-L13
13: bytes32 internal constant PREFIX_TIME_LOCK = keccak256('time-lock'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L44-L44
44: bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L45-L45
45: bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L46-L46
46: bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L47-L47
47: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L48-L48
48: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L49-L49
49: bytes32 internal constant PREFIX_TOKEN_MINT_LIMIT = keccak256('token-mint-limit'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L50-L50
50: bytes32 internal constant PREFIX_TOKEN_MINT_AMOUNT = keccak256('token-mint-amount'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L52-L52
52: bytes32 internal constant SELECTOR_BURN_TOKEN = keccak256('burnToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L53-L53
53: bytes32 internal constant SELECTOR_DEPLOY_TOKEN = keccak256('deployToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L54-L54
54: bytes32 internal constant SELECTOR_MINT_TOKEN = keccak256('mintToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L55-L55
55: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL = keccak256('approveContractCall'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L56-L56
56: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT = keccak256('approveContractCallWithMint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L57-L57
57: bytes32 internal constant SELECTOR_TRANSFER_OPERATORSHIP = keccak256('transferOperatorship'); // <= FOUND
18: bytes32 internal constant FINAL_IMPLEMENTATION_SALT = keccak256('final-implementation'); // <= FOUND
62: bytes32 internal constant PREFIX_CUSTOM_TOKEN_ID = keccak256('its-custom-token-id'); // <= FOUND
63: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_ID = keccak256('its-standardized-token-id'); // <= FOUND
64: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_SALT = keccak256('its-standardized-token-salt'); // <= FOUND
71: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service'); // <= FOUND
12: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator'); // <= FOUND
27: bytes32 private constant CONTRACT_ID = keccak256('standardized-token'); // <= FOUND
1
If these serve no purpose, they should be safely removed
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L13-L13
13: error MulticallFailed(bytes err); // <= FOUND
35
In the event of a security breach or any unforeseen emergency, swiftly suspending all protocol operations becomes crucial. Having a mechanism in place to halt all functions collectively, instead of pausing individual contracts separately, substantially enhances the efficiency of mitigating ongoing attacks or vulnerabilities. This not only quickens the response time to potential threats but also reduces operational stress during these critical periods. Therefore, consider integrating a 'circuit breaker' or 'emergency stop' function into the smart contract system architecture. Such a feature would provide the capability to suspend the entire protocol instantly, which could prove invaluable during a time-sensitive crisis management situation.
Findings are labeled with ' <= FOUND'
Click to show findings
15: contract InterchainGovernance is AxelarExecutable, TimeLock, Caller, IInterchainGovernance
14: contract AxelarServiceGovernance is InterchainGovernance, MultisigBase, IAxelarServiceGovernance
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L12-L12
12: contract MultisigBase is IMultisigBase
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L13-L13
13: contract Multisig is Caller, MultisigBase, IMultisig
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L12-L12
12: contract TimeLock is ITimeLock
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Caller.sol#L7-L7
7: contract Caller is ICaller
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L17-L17
17: contract AxelarGateway is IAxelarGateway, IGovernable, AdminMultisigBase
38: contract InterchainProposalSender is IInterchainProposalSender
22: contract InterchainProposalExecutor is IInterchainProposalExecutor, AxelarExecutable, Ownable
5: contract ConstAddressDeployer
12: contract Create3Deployer
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L16-L16
16: contract CreateDeployer
15: contract Proxy is BaseProxy
16: contract InitProxy is BaseProxy, IInitProxy
17: contract FinalProxy is Proxy, IFinalProxy
12: contract FixedProxy is IProxy
contract InterchainTokenService is IInterchainTokenService, AxelarExecutable, Upgradable, Operatable, ExpressCallHandler, Pausable, Multicall
11: contract InterchainTokenServiceProxy is FinalProxy
11: contract RemoteAddressValidatorProxy is Proxy
13: contract StandardizedTokenProxy is FixedProxy, IStandardizedTokenProxy
13: contract TokenManagerProxy is ITokenManagerProxy
12: contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable
7: contract StandardizedTokenLockUnlock is StandardizedToken
7: contract StandardizedTokenMintBurn is StandardizedToken
16: contract TokenManagerLockUnlock is TokenManagerAddressStorage
17: contract TokenManagerMintBurn is TokenManagerAddressStorage
17: contract TokenManagerLiquidityPool is TokenManagerAddressStorage
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L13-L13
13: contract Distributable is IDistributable
12: contract ExpressCallHandler is IExpressCallHandler
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L12-L12
12: contract FlowLimit is IFlowLimit
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L12-L12
12: contract Multicall is IMulticall
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L13-L13
13: contract Operatable is IOperatable
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L12-L12
12: contract Pausable is IPausable
15: contract StandardizedTokenDeployer is IStandardizedTokenDeployer
15: contract TokenManagerDeployer is ITokenManagerDeployer
18
Smart contracts are complex entities, and clarity in their operations is fundamental to ensure that they function as intended. Casting a single argument instead of utilizing 'abi.encodePacked()' improves the transparency of the operation. It elucidates the intent of the code, reducing ambiguity and making it easier for auditors and developers to understand the code’s purpose. Such practices promote readability and maintainability, thus reducing the likelihood of errors and misunderstandings. Therefore, it's recommended to employ explicit casts for single arguments where possible, to increase the contract's comprehensibility and ensure a smoother review process.
Findings are labeled with ' <= FOUND'
Click to show findings
73: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
148: return keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L93-L93
93: bytes32 key = keccak256(abi.encodePacked(PREFIX_TIME_LOCK, hash)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L349-L349
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i])); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L395-L395
395: bytes32 salt = keccak256(abi.encodePacked(symbol)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L434-L434
434: address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode))); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L556-L556
556: return keccak256(abi.encodePacked(PREFIX_TOKEN_MINT_LIMIT, symbol)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L565-L565
565: return keccak256(abi.encodePacked(PREFIX_TOKEN_TYPE, symbol)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L569-L569
569: return keccak256(abi.encodePacked(PREFIX_TOKEN_ADDRESS, symbol)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L573-L573
573: return keccak256(abi.encodePacked(PREFIX_COMMAND_EXECUTED, commandId)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L615-L615
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash))))); // <= FOUND
68: abi.encodePacked( // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L72-L72
72: address deployer = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', sender, salt, DEPLOYER_BYTECODE_HASH))))); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L74-L74
74: deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01'))))); // <= FOUND
23: ) FinalProxy(implementationAddress, owner, abi.encodePacked(operator)) {} // <= FOUND
125: abi.encodePacked(version, data) // <= FOUND
63: bytecode = abi.encodePacked(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params)); // <= FOUND
39: bytes memory bytecode = abi.encodePacked(type(TokenManagerProxy).creationCode, args); // <= FOUND
4
In Solidity, the use of custom error messages provides a valuable method of conveying meaningful information about failures during execution. In the current implementation, the custom errors lack specifics, making it challenging to understand the root cause of a failure. It's advisable to incorporate parameters into your error messages to indicate which user action or specific value caused the exception. This not only enhances error transparency but also aids debugging and fosters a more robust and maintainable codebase. Providing such precise error context greatly helps developers identify and resolve issues faster.
Findings are labeled with ' <= FOUND'
Click to show findings
10: error InvalidImplementation(); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L8-L8
8: error EmptyBytecode(); // <= FOUND
7: error FailedDeploy(); // <= FOUND
8: error FailedInit(); // <= FOUND
138
Change found instances to use double quotes
Findings are labeled with ' <= FOUND'
Click to show findings
6: import { IAxelarExecutable } from '../../gmp-sdk/interfaces/IAxelarExecutable.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/interfaces/IMultisig.sol#L6-L6
6: import { ICaller } from './ICaller.sol'; // <= FOUND
5: import { AxelarExecutable } from '../../gmp-sdk/executable/AxelarExecutable.sol'; // <= FOUND
6: import { TimeLock } from '../../gmp-sdk/util/TimeLock.sol'; // <= FOUND
7: import { IInterchainGovernance } from '../interfaces/IInterchainGovernance.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L7-L7
7: import { Caller } from '../util/Caller.sol'; // <= FOUND
5: import { IInterchainGovernance } from './IInterchainGovernance.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/interfaces/IMultisig.sol#L5-L5
5: import { IMultisigBase } from './IMultisigBase.sol'; // <= FOUND
5: import { IAxelarServiceGovernance } from '../interfaces/IAxelarServiceGovernance.sol'; // <= FOUND
6: import { InterchainGovernance } from './InterchainGovernance.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L6-L6
6: import { MultisigBase } from '../auth/MultisigBase.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L5-L5
5: import { IMultisigBase } from '../interfaces/IMultisigBase.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L5-L5
5: import { IMultisig } from '../interfaces/IMultisig.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L5-L5
5: import { ITimeLock } from '../interfaces/ITimeLock.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L13-L13
13: bytes32 internal constant PREFIX_TIME_LOCK = keccak256('time-lock'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Caller.sol#L5-L5
5: import { ICaller } from '../interfaces/ICaller.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L5-L5
5: import { SafeTokenCall, SafeTokenTransfer, SafeTokenTransferFrom } from '../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L6-L6
6: import { IERC20 } from '../gmp-sdk/interfaces/IERC20.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L7-L7
7: import { IAxelarGateway } from './interfaces/IAxelarGateway.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L8-L8
8: import { IGovernable } from './interfaces/IGovernable.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L9-L9
9: import { IAxelarAuth } from './interfaces/IAxelarAuth.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L10-L10
10: import { IBurnableMintableCappedERC20 } from './interfaces/IBurnableMintableCappedERC20.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L11-L11
11: import { ITokenDeployer } from './interfaces/ITokenDeployer.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L13-L13
13: import { ECDSA } from './ECDSA.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L14-L14
14: import { DepositHandler } from './DepositHandler.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L15-L15
15: import { AdminMultisigBase } from './AdminMultisigBase.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L44-L44
44: bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L45-L45
45: bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L46-L46
46: bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L47-L47
47: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L48-L48
48: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L49-L49
49: bytes32 internal constant PREFIX_TOKEN_MINT_LIMIT = keccak256('token-mint-limit'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L50-L50
50: bytes32 internal constant PREFIX_TOKEN_MINT_AMOUNT = keccak256('token-mint-amount'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L52-L52
52: bytes32 internal constant SELECTOR_BURN_TOKEN = keccak256('burnToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L53-L53
53: bytes32 internal constant SELECTOR_DEPLOY_TOKEN = keccak256('deployToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L54-L54
54: bytes32 internal constant SELECTOR_MINT_TOKEN = keccak256('mintToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L55-L55
55: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL = keccak256('approveContractCall'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L56-L56
56: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT = keccak256('approveContractCallWithMint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L57-L57
57: bytes32 internal constant SELECTOR_TRANSFER_OPERATORSHIP = keccak256('transferOperatorship'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L246-L246
246: return keccak256('axelar-gateway'); // <= FOUND
5: import { IAxelarGateway } from '../gmp-sdk/interfaces/IAxelarGateway.sol'; // <= FOUND
6: import { IAxelarGasService } from '../gmp-sdk/interfaces/IAxelarGasService.sol'; // <= FOUND
7: import { IInterchainProposalSender } from './interfaces/IInterchainProposalSender.sol'; // <= FOUND
8: import { InterchainCalls } from './lib/InterchainCalls.sol'; // <= FOUND
5: import { InterchainCalls } from '../lib/InterchainCalls.sol'; // <= FOUND
4: import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol'; // <= FOUND
5: import { StringToAddress } from '../gmp-sdk/util/AddressString.sol'; // <= FOUND
6: import { AxelarExecutable } from '../gmp-sdk/executable/AxelarExecutable.sol'; // <= FOUND
7: import { IInterchainProposalExecutor } from './interfaces/IInterchainProposalExecutor.sol'; // <= FOUND
69: hex'ff', // <= FOUND
5: import { Create3 } from './Create3.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L5-L5
5: import { ContractAddress } from '../util/ContractAddress.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L72-L72
72: address deployer = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', sender, salt, DEPLOYER_BYTECODE_HASH))))); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L74-L74
74: deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01'))))); // <= FOUND
5: import { IProxy } from '../interfaces/IProxy.sol'; // <= FOUND
5: import { IUpgradable } from '../interfaces/IUpgradable.sol'; // <= FOUND
8: import { BaseProxy } from './BaseProxy.sol'; // <= FOUND
6: import { Ownable } from '../util/Ownable.sol'; // <= FOUND
5: import { IOwnable } from './IOwnable.sol'; // <= FOUND
5: import { IInitProxy } from '../interfaces/IInitProxy.sol'; // <= FOUND
5: import { IProxy } from './IProxy.sol'; // <= FOUND
6: import { IFinalProxy } from '../interfaces/IFinalProxy.sol'; // <= FOUND
7: import { Create3 } from '../deploy/Create3.sol'; // <= FOUND
9: import { Proxy } from './Proxy.sol'; // <= FOUND
18: bytes32 internal constant FINAL_IMPLEMENTATION_SALT = keccak256('final-implementation'); // <= FOUND
5: import { IInterchainToken } from '../interfaces/IInterchainToken.sol'; // <= FOUND
5: import { ITokenManager } from '../interfaces/ITokenManager.sol'; // <= FOUND
7: import { ERC20 } from '../token-implementations/ERC20.sol'; // <= FOUND
5: import { IERC20 } from '../../gmp-sdk/interfaces/IERC20.sol'; // <= FOUND
5: import { IAxelarGateway } from '../../gmp-sdk/interfaces/IAxelarGateway.sol'; // <= FOUND
6: import { IAxelarGasService } from '../../gmp-sdk/interfaces/IAxelarGasService.sol'; // <= FOUND
8: import { SafeTokenTransferFrom } from '../../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
6: import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol'; // <= FOUND
7: import { ITokenManagerDeployer } from '../interfaces/ITokenManagerDeployer.sol'; // <= FOUND
7: import { IStandardizedTokenDeployer } from '../interfaces/IStandardizedTokenDeployer.sol'; // <= FOUND
4: import { IRemoteAddressValidator } from '../interfaces/IRemoteAddressValidator.sol'; // <= FOUND
15: import { IInterchainTokenExpressExecutable } from '../interfaces/IInterchainTokenExpressExecutable.sol'; // <= FOUND
7: import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol'; // <= FOUND
18: import { IERC20Named } from '../interfaces/IERC20Named.sol'; // <= FOUND
11: import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol'; // <= FOUND
21: import { StringToBytes32, Bytes32ToString } from '../../gmp-sdk/util/Bytes32String.sol'; // <= FOUND
6: import { Upgradable } from '../../gmp-sdk/upgradable/Upgradable.sol'; // <= FOUND
5: import { Create3Deployer } from '../../gmp-sdk/deploy/Create3Deployer.sol'; // <= FOUND
26: import { ExpressCallHandler } from '../utils/ExpressCallHandler.sol'; // <= FOUND
27: import { Pausable } from '../utils/Pausable.sol'; // <= FOUND
9: import { Operatable } from '../utils/Operatable.sol'; // <= FOUND
29: import { Multicall } from '../utils/Multicall.sol'; // <= FOUND
62: bytes32 internal constant PREFIX_CUSTOM_TOKEN_ID = keccak256('its-custom-token-id'); // <= FOUND
63: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_ID = keccak256('its-standardized-token-id'); // <= FOUND
64: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_SALT = keccak256('its-standardized-token-salt'); // <= FOUND
71: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service'); // <= FOUND
334: _deployRemoteStandardizedToken(tokenId, tokenName, tokenSymbol, tokenDecimals, '', '', destinationChain, gasValue); // <= FOUND
8: import { IExpressCallHandler } from './IExpressCallHandler.sol'; // <= FOUND
9: import { ITokenManagerDeployer } from './ITokenManagerDeployer.sol'; // <= FOUND
5: import { ITokenManagerType } from './ITokenManagerType.sol'; // <= FOUND
11: import { IPausable } from './IPausable.sol'; // <= FOUND
12: import { IMulticall } from './IMulticall.sol'; // <= FOUND
5: import { FinalProxy } from '../../gmp-sdk/upgradable/FinalProxy.sol'; // <= FOUND
5: import { Proxy } from '../../gmp-sdk/upgradable/Proxy.sol'; // <= FOUND
12: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator'); // <= FOUND
5: import { FixedProxy } from '../../gmp-sdk/upgradable/FixedProxy.sol'; // <= FOUND
6: import { IStandardizedToken } from '../interfaces/IStandardizedToken.sol'; // <= FOUND
7: import { IStandardizedTokenProxy } from '../interfaces/IStandardizedTokenProxy.sol'; // <= FOUND
27: bytes32 private constant CONTRACT_ID = keccak256('standardized-token'); // <= FOUND
5: import { AddressToString } from '../../gmp-sdk/util/AddressString.sol'; // <= FOUND
98: remoteAddresses[chain] = ''; // <= FOUND
5: import { IERC20BurnableMintable } from '../interfaces/IERC20BurnableMintable.sol'; // <= FOUND
7: import { InterchainToken } from '../interchain-token/InterchainToken.sol'; // <= FOUND
8: import { ERC20Permit } from '../token-implementations/ERC20Permit.sol'; // <= FOUND
12: import { Implementation } from '../utils/Implementation.sol'; // <= FOUND
12: import { Distributable } from '../utils/Distributable.sol'; // <= FOUND
5: import { StandardizedToken } from './StandardizedToken.sol'; // <= FOUND
5: import { IInterchainToken } from './IInterchainToken.sol'; // <= FOUND
6: import { IDistributable } from './IDistributable.sol'; // <= FOUND
7: import { IERC20BurnableMintable } from './IERC20BurnableMintable.sol'; // <= FOUND
10: import { FlowLimit } from '../utils/FlowLimit.sol'; // <= FOUND
5: import { TokenManager } from '../TokenManager.sol'; // <= FOUND
6: import { IERC20 } from '../../../gmp-sdk/interfaces/IERC20.sol'; // <= FOUND
7: import { IAxelarGateway } from '../../../gmp-sdk/interfaces/IAxelarGateway.sol'; // <= FOUND
5: import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; // <= FOUND
8: import { SafeTokenTransferFrom, SafeTokenTransfer } from '../../../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
6: import { IERC20BurnableMintable } from '../../interfaces/IERC20BurnableMintable.sol'; // <= FOUND
9: import { SafeTokenCall } from '../../../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
8: import { SafeTokenTransferFrom } from '../../../gmp-sdk/util/SafeTransfer.sol'; // <= FOUND
6: import { IOperatable } from './IOperatable.sol'; // <= FOUND
7: import { IFlowLimit } from './IFlowLimit.sol'; // <= FOUND
8: import { IImplementation } from './IImplementation.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L5-L5
5: import { IDistributable } from '../interfaces/IDistributable.sol'; // <= FOUND
5: import { IExpressCallHandler } from '../interfaces/IExpressCallHandler.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L5-L5
5: import { IFlowLimit } from '../interfaces/IFlowLimit.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L15-L15
15: uint256 internal constant PREFIX_FLOW_OUT_AMOUNT = uint256(keccak256('prefix-flow-out-amount')); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L16-L16
16: uint256 internal constant PREFIX_FLOW_IN_AMOUNT = uint256(keccak256('prefix-flow-in-amount')); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Implementation.sol#L5-L5
5: import { IImplementation } from '../interfaces/IImplementation.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L5-L5
5: import { IMulticall } from '../interfaces/IMulticall.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L5-L5
5: import { IOperatable } from '../interfaces/IOperatable.sol'; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L5-L5
5: import { IPausable } from '../interfaces/IPausable.sol'; // <= FOUND
9: import { StandardizedTokenProxy } from '../proxies/StandardizedTokenProxy.sol'; // <= FOUND
9: import { TokenManagerProxy } from '../proxies/TokenManagerProxy.sol'; // <= FOUND
1
Reason: Contracts with large codebases, complex inline-assembly, intricate math, or multifaceted inter-contract interactions can harbor elusive bugs, even with full code coverage. These bugs can surface depending on the sequence of operations performed by the user.
Resolution: Implement invariant fuzzing tests using tools like Echidna. Define comprehensive invariants – conditions that must always hold true – and let the fuzzer generate various input and function call sequences to test them. This way, you can significantly mitigate the risks posed by unexplored operation orders and bolster the contract's robustness.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L322-L322
322: function execute(bytes calldata input) external override // <= FOUND
1
Improving code readability and compactness is an integral part of optimal programming practices. The use of ternary operators in place of if-else conditions is one such measure. Ternary operators allow us to write conditional statements in a more concise manner, thereby enhancing readability and simplicity. They follow the syntax condition ? exprIfTrue : exprIfFalse
, which interprets as "if the condition is true, evaluate to exprIfTrue
, else evaluate to exprIfFalse
". By adopting this approach, we make our code more streamlined and intuitive, which could potentially aid in better understanding and maintenance of the codebase.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L59-L61
59: if (voteCount < signers.threshold) {
60:
61: voting.voteCount = voteCount; // <= FOUND
62: return;
63: }
20
Findings are labeled with ' <= FOUND'
Click to show findings
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { Proxy } from '../../gmp-sdk/upgradable/Proxy.sol';
6:
7: /**
8: * @title RemoteAddressValidatorProxy
9: * @dev Proxy contract for the RemoteAddressValidator contract. Inherits from the Proxy contract.
10: */
11: contract RemoteAddressValidatorProxy is Proxy {
12: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator');
13:
14: /**
15: * @dev Constructs the RemoteAddressValidatorProxy contract.
16: * @param implementationAddress Address of the RemoteAddressValidator implementation
17: * @param owner Address of the owner of the proxy
18: * @param params The params to be passed to the _setup function of the implementation.
19: */
20: constructor(
21: address implementationAddress,
22: address owner,
23: bytes memory params
24: ) Proxy(implementationAddress, owner, params) {}
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title AddressBytesUtils
7: * @dev This library provides utility functions to convert between `address` and `bytes`.
8: */
9: library AddressBytesUtils {
10: error InvalidBytesLength(bytes bytesAddress);
11:
12: /**
13: * @dev Converts a bytes address to an address type.
14: * @param bytesAddress The bytes representation of an address
15: * @return addr The converted address
16: */
17: function toAddress(bytes memory bytesAddress) internal pure returns (address addr) {
18: if (bytesAddress.length != 20) revert InvalidBytesLength(bytesAddress);
19:
20: assembly {
21: addr := mload(add(bytesAddress, 20))
22: }
23: }
24:
25: /**
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: interface IImplementation {
6: error NotProxy();
7: }
8:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IProxy } from './IProxy.sol';
6:
7: // General interface for upgradable contracts
8: interface IFinalProxy is IProxy {
9: function isFinal() external view returns (bool);
10:
11: function finalUpgrade(bytes memory bytecode, bytes calldata setupParams) external returns (address);
12: }
13:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/interfaces/ICaller.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: interface ICaller {
6: error InsufficientBalance();
7: error ExecutionFailed();
8: }
9:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { StandardizedToken } from './StandardizedToken.sol';
6:
7: contract StandardizedTokenMintBurn is StandardizedToken {
8: function tokenManagerRequiresApproval() public pure override returns (bool) {
9: return false;
10: }
11: }
12:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IOwnable } from './IOwnable.sol';
6:
7: // General interface for upgradable contracts
8: interface IUpgradable is IOwnable {
9: error InvalidCodeHash();
10: error InvalidImplementation();
11: error SetupFailed();
12: error NotProxy();
13:
14: event Upgraded(address indexed newImplementation);
15:
16: function implementation() external view returns (address);
17:
18: function upgrade(
19: address newImplementation,
20: bytes32 newImplementationCodeHash,
21: bytes calldata params
22: ) external;
23:
24: function setup(bytes calldata data) external;
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: contract ConstAddressDeployer {
6: error EmptyBytecode();
7: error FailedDeploy();
8: error FailedInit();
9:
10: event Deployed(bytes32 indexed bytecodeHash, bytes32 indexed salt, address indexed deployedAddress);
11:
12: /**
13: * @dev Deploys a contract using `CREATE2`. The address where the contract
14: * will be deployed can be known in advance via {deployedAddress}.
15: *
16: * The bytecode for a contract can be obtained from Solidity with
17: * `type(contractName).creationCode`.
18: *
19: * Requirements:
20: *
21: * - `bytecode` must not be empty.
22: * - `salt` must have not been used for `bytecode` already by the same `msg.sender`.
23: */
24: function deploy(bytes memory bytecode, bytes32 salt) external returns (address deployedAddress_) {
25: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt)));
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { StandardizedToken } from './StandardizedToken.sol';
6:
7: contract StandardizedTokenLockUnlock is StandardizedToken {
8: function tokenManagerRequiresApproval() public pure override returns (bool) {
9: return true;
10: }
11: }
12:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IAxelarGateway } from '../gmp-sdk/interfaces/IAxelarGateway.sol';
6: import { IAxelarGasService } from '../gmp-sdk/interfaces/IAxelarGasService.sol';
7: import { IInterchainProposalSender } from './interfaces/IInterchainProposalSender.sol';
8: import { InterchainCalls } from './lib/InterchainCalls.sol';
9:
10: /**
11: * @title InterchainProposalSender
12: * @dev This contract is responsible for facilitating the execution of approved proposals across multiple chains.
13: * It achieves this by working in conjunction with the AxelarGateway and AxelarGasService contracts.
14: *
15: * The contract allows for the sending of a single proposal to multiple destination chains. This is achieved
16: * through the `sendProposals` function, which takes in arrays representing the destination chains,
17: * destination contracts, fees, target contracts, amounts of tokens to send, function signatures, and encoded
18: * function arguments.
19: *
20: * Each destination chain has a unique corresponding set of contracts to call, amounts of native tokens to send,
21: * function signatures to call, and encoded function arguments. This information is provided in a 2D array where
22: * the first dimension is the destination chain index, and the second dimension corresponds to the specific details
23: * for each chain.
24: *
25: * In addition, the contract also allows for the execution of a single proposal at a single destination chain
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: library InterchainCalls {
6: /**
7: * @dev An interchain call to be executed at the destination chain
8: * @param destinationChain destination chain
9: * @param destinationContract destination contract
10: * @param gas The amount of native token to transfer to the target contract as gas payment for the interchain call
11: * @param calls An array of calls to be executed at the destination chain
12: */
13: struct InterchainCall {
14: string destinationChain;
15: string destinationContract;
16: uint256 gas;
17: Call[] calls;
18: }
19:
20: /**
21: * @dev A call to be executed at the destination chain
22: * @param target The address of the contract to call
23: * @param value The amount of native token to transfer to the target contract
24: * @param callData The data to pass to the target contract
25: */
1: // SPDX-License-Identifier: MIT
2: pragma solidity ^0.8.0;
3:
4: import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
5: import { StringToAddress } from '../gmp-sdk/util/AddressString.sol';
6: import { AxelarExecutable } from '../gmp-sdk/executable/AxelarExecutable.sol';
7: import { IInterchainProposalExecutor } from './interfaces/IInterchainProposalExecutor.sol';
8: import { InterchainCalls } from './lib/InterchainCalls.sol';
9:
10: /**
11: * @title InterchainProposalExecutor
12: * @dev This contract is intended to be the destination contract for `InterchainProposalSender` contract.
13: * The proposal will be finally executed from this contract on the destination chain.
14: *
15: * The contract maintains whitelists for proposal senders and proposal callers. Proposal senders
16: * are InterchainProposalSender contracts at the source chain and proposal callers are contracts
17: * that call the InterchainProposalSender at the source chain.
18: * For most governance system, the proposal caller should be the Timelock contract.
19: *
20: * This contract is abstract and some of its functions need to be implemented in a derived contract.
21: */
22: contract InterchainProposalExecutor is IInterchainProposalExecutor, AxelarExecutable, Ownable {
23: // Whitelisted proposal callers. The proposal caller is the contract that calls the `InterchainProposalSender` at the source chain.
24: mapping(string => mapping(address => bool)) public whitelistedCallers;
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IProxy } from './IProxy.sol';
6:
7: // General interface for upgradable contracts
8: interface IInitProxy is IProxy {
9: function init(
10: address implementationAddress,
11: address newOwner,
12: bytes memory params
13: ) external;
14: }
15:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { InterchainCalls } from '../lib/InterchainCalls.sol';
6:
7: interface IInterchainProposalSender {
8: // An error emitted when the given gas is invalid
9: error InvalidFee();
10:
11: /**
12: * @dev Broadcast the proposal to be executed at multiple destination chains
13: * @param calls An array of calls to be executed at the destination chain
14: */
15: function sendProposals(InterchainCalls.InterchainCall[] memory calls) external payable;
16:
17: /**
18: * @dev Broadcast the proposal to be executed at single destination chain
19: * @param destinationChain destination chain
20: * @param destinationContract destination contract
21: * @param calls An array of calls to be executed at the destination chain
22: */
23: function sendProposal(
24: string calldata destinationChain,
25: string calldata destinationContract,
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.9;
4:
5: import { SafeTokenCall, SafeTokenTransfer, SafeTokenTransferFrom } from '../gmp-sdk/util/SafeTransfer.sol';
6: import { IERC20 } from '../gmp-sdk/interfaces/IERC20.sol';
7: import { IAxelarGateway } from './interfaces/IAxelarGateway.sol';
8: import { IGovernable } from './interfaces/IGovernable.sol';
9: import { IAxelarAuth } from './interfaces/IAxelarAuth.sol';
10: import { IBurnableMintableCappedERC20 } from './interfaces/IBurnableMintableCappedERC20.sol';
11: import { ITokenDeployer } from './interfaces/ITokenDeployer.sol';
12:
13: import { ECDSA } from './ECDSA.sol';
14: import { DepositHandler } from './DepositHandler.sol';
15: import { AdminMultisigBase } from './AdminMultisigBase.sol';
16:
17: contract AxelarGateway is IAxelarGateway, IGovernable, AdminMultisigBase {
18: using SafeTokenCall for IERC20;
19: using SafeTokenTransfer for IERC20;
20: using SafeTokenTransferFrom for IERC20;
21:
22: error InvalidImplementation();
23:
24: enum TokenType {
25: InternalBurnable,
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol';
6: import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol';
7:
8: /**
9: * @title TokenManagerProxy
10: * @dev This contract is a proxy for token manager contracts. It implements ITokenManagerProxy and
11: * inherits from FixedProxy from the gmp sdk repo
12: */
13: contract TokenManagerProxy is ITokenManagerProxy {
14: IInterchainTokenService public immutable interchainTokenServiceAddress;
15: uint256 public immutable implementationType;
16: bytes32 public immutable tokenId;
17:
18: /**
19: * @dev Constructs the TokenManagerProxy contract.
20: * @param interchainTokenServiceAddress_ The address of the interchain token service
21: * @param implementationType_ The token manager type
22: * @param tokenId_ The identifier for the token
23: * @param params The initialization parameters for the token manager contract
24: */
25: constructor(
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/interfaces/IProxy.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: // General interface for upgradable contracts
6: interface IProxy {
7: error InvalidOwner();
8: error InvalidImplementation();
9: error SetupFailed();
10: error NotOwner();
11: error AlreadyInitialized();
12:
13: function implementation() external view returns (address implementation_);
14:
15: function setup(bytes calldata setupParams) external;
16: }
17:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Caller.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { ICaller } from '../interfaces/ICaller.sol';
6:
7: contract Caller is ICaller {
8: /**
9: * @dev Calls a target address with specified calldata and optionally sends value.
10: */
11: function _call(
12: address target,
13: bytes calldata callData,
14: uint256 nativeValue
15: ) internal {
16: if (nativeValue > address(this).balance) revert InsufficientBalance();
17:
18: (bool success, ) = target.call{ value: nativeValue }(callData);
19: if (!success) {
20: revert ExecutionFailed();
21: }
22: }
23: }
24:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IProxy } from '../interfaces/IProxy.sol';
6:
7: /**
8: * @title BaseProxy Contract
9: * @dev This abstract contract implements a basic proxy that stores an implementation address. Fallback function
10: * calls are delegated to the implementation. This contract is meant to be inherited by other proxy contracts.
11: */
12: abstract contract BaseProxy is IProxy {
13: // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
14: bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
15: // keccak256('owner')
16: bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0;
17:
18: /**
19: * @dev Returns the current implementation address.
20: * @return implementation_ The address of the current implementation contract
21: */
22: function implementation() public view virtual returns (address implementation_) {
23: assembly {
24: implementation_ := sload(_IMPLEMENTATION_SLOT)
25: }
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { FinalProxy } from '../../gmp-sdk/upgradable/FinalProxy.sol';
6:
7: /**
8: * @title InterchainTokenServiceProxy
9: * @dev Proxy contract for interchain token service contracts. Inherits from the FinalProxy contract.
10: */
11: contract InterchainTokenServiceProxy is FinalProxy {
12: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service');
13:
14: /**
15: * @dev Constructs the InterchainTokenServiceProxy contract.
16: * @param implementationAddress Address of the interchain token service implementation
17: * @param owner Address of the owner of the proxy
18: */
19: constructor(
20: address implementationAddress,
21: address owner,
22: address operator
23: ) FinalProxy(implementationAddress, owner, abi.encodePacked(operator)) {}
24:
25: /**
5
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L35-L35
35: bytes32 internal constant KEY_IMPLEMENTATION = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L38-L38
38: bytes32 internal constant KEY_GOVERNANCE = bytes32(0xabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L41-L41
41: bytes32 internal constant KEY_MINT_LIMITER = bytes32(0x627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L508-L508
508: return codehash != bytes32(0) && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L615-L615
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash))))); // <= FOUND
99
When developing smart contracts in Solidity, it's crucial to validate the inputs of your functions. This includes ensuring that the bytes parameters are not empty, especially when they represent crucial data such as addresses, identifiers, or raw data that the contract needs to process.
Missing empty bytes checks can lead to unexpected behaviour in your contract. For instance, certain operations might fail, produce incorrect results, or consume unnecessary gas when performed with empty bytes. Moreover, missing input validation can potentially expose your contract to malicious activity, including exploitation of unhandled edge cases.
To mitigate these issues, always validate that bytes parameters are not empty when the logic of your contract requires it.
Findings are labeled with ' <= FOUND'
Click to show findings
52: function getProposalEta(
53: address target,
54: bytes calldata callData,
55: uint256 nativeValue
56: ) external view returns (uint256) {
57: return _getTimeLockEta(_getProposalHash(target, callData, nativeValue));
58: }
68: function executeProposal(
69: address target,
70: bytes calldata callData,
71: uint256 nativeValue
72: ) external payable {
73: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue));
74:
75: _finalizeTimeLock(proposalHash);
76: _call(target, callData, nativeValue);
77:
78: emit ProposalExecuted(proposalHash, target, callData, nativeValue, block.timestamp);
79: }
87: function _execute(
88: string calldata sourceChain,
89: string calldata sourceAddress,
90: bytes calldata payload
91: ) internal override {
92: if (keccak256(bytes(sourceChain)) != governanceChainHash || keccak256(bytes(sourceAddress)) != governanceAddressHash)
93: revert NotGovernance();
94:
95: (uint256 command, address target, bytes memory callData, uint256 nativeValue, uint256 eta) = abi.decode(
96: payload,
97: (uint256, address, bytes, uint256, uint256)
98: );
99:
100: if (target == address(0)) revert InvalidTarget();
101:
102: _processCommand(command, target, callData, nativeValue, eta);
103: }
113: function _processCommand(
114: uint256 commandId,
115: address target,
116: bytes memory callData,
117: uint256 nativeValue,
118: uint256 eta
119: ) internal virtual {
120: if (commandId > uint256(type(GovernanceCommand).max)) {
121: revert InvalidCommand();
122: }
123:
124: GovernanceCommand command = GovernanceCommand(commandId);
125: bytes32 proposalHash = _getProposalHash(target, callData, nativeValue);
126:
127: if (command == GovernanceCommand.ScheduleTimeLockProposal) {
128: eta = _scheduleTimeLock(proposalHash, eta);
129:
130: emit ProposalScheduled(proposalHash, target, callData, nativeValue, eta);
131: return;
132: } else if (command == GovernanceCommand.CancelTimeLockProposal) {
133: _cancelTimeLock(proposalHash);
134:
135: emit ProposalCancelled(proposalHash, target, callData, nativeValue, eta);
136: return;
137: }
143: function _getProposalHash(
144: address target,
145: bytes memory callData,
146: uint256 nativeValue
147: ) internal pure returns (bytes32) {
148: return keccak256(abi.encodePacked(target, callData, nativeValue));
149: }
155: function _executeWithToken(
156: string calldata,
157: string calldata,
158: bytes calldata,
159: string calldata,
160: uint256
161: ) internal pure override {
162: revert TokenNotSupported();
163: }
48: function executeMultisigProposal(
49: address target,
50: bytes calldata callData,
51: uint256 nativeValue
52: ) external payable onlySigners {
53: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue));
54:
55: if (!multisigApprovals[proposalHash]) revert NotApproved();
56:
57: multisigApprovals[proposalHash] = false;
58:
59: _call(target, callData, nativeValue);
60:
61: emit MultisigExecuted(proposalHash, target, callData, nativeValue);
62: }
72: function _processCommand(
73: uint256 commandId,
74: address target,
75: bytes memory callData,
76: uint256 nativeValue,
77: uint256 eta
78: ) internal override {
79: if (commandId > uint256(type(ServiceGovernanceCommand).max)) {
80: revert InvalidCommand();
81: }
82:
83: ServiceGovernanceCommand command = ServiceGovernanceCommand(commandId);
84: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue));
85:
86: if (command == ServiceGovernanceCommand.ScheduleTimeLockProposal) {
87: eta = _scheduleTimeLock(proposalHash, eta);
88:
89: emit ProposalScheduled(proposalHash, target, callData, nativeValue, eta);
90: return;
91: } else if (command == ServiceGovernanceCommand.CancelTimeLockProposal) {
92: _cancelTimeLock(proposalHash);
93:
94: emit ProposalCancelled(proposalHash, target, callData, nativeValue, eta);
95: return;
96: } else if (command == ServiceGovernanceCommand.ApproveMultisigProposal) {
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L111-L111
111: function hasSignerVoted(address account, bytes32 topic) external view override returns (bool) {
112: return votingPerTopic[signerEpoch][topic].hasVoted[account];
113: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L30-L30
30: function execute(
31: address target,
32: bytes calldata callData,
33: uint256 nativeValue
34: ) external payable onlySigners {
35: _call(target, callData, nativeValue);
36: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L38-L38
38: function getTimeLock(bytes32 hash) external view override returns (uint256) {
39: return _getTimeLockEta(hash);
40: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L50-L50
50: function _scheduleTimeLock(bytes32 hash, uint256 eta) internal returns (uint256) {
51: if (hash == 0) revert InvalidTimeLockHash();
52: if (_getTimeLockEta(hash) != 0) revert TimeLockAlreadyScheduled();
53:
54: uint256 minimumEta = block.timestamp + _minimumTimeLockDelay;
55:
56: if (eta < minimumEta) eta = minimumEta;
57:
58: _setTimeLockEta(hash, eta);
59:
60: return eta;
61: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L67-L67
67: function _cancelTimeLock(bytes32 hash) internal {
68: if (hash == 0) revert InvalidTimeLockHash();
69:
70: _setTimeLockEta(hash, 0);
71: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L79-L79
79: function _finalizeTimeLock(bytes32 hash) internal {
80: uint256 eta = _getTimeLockEta(hash);
81:
82: if (hash == 0 || eta == 0) revert InvalidTimeLockHash();
83:
84: if (block.timestamp < eta) revert TimeLockNotReady();
85:
86: _setTimeLockEta(hash, 0);
87: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L92-L92
92: function _getTimeLockEta(bytes32 hash) internal view returns (uint256 eta) {
93: bytes32 key = keccak256(abi.encodePacked(PREFIX_TIME_LOCK, hash));
94:
95: assembly {
96: eta := sload(key)
97: }
98: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L103-L103
103: function _setTimeLockEta(bytes32 hash, uint256 eta) private {
104: bytes32 key = keccak256(abi.encodePacked(PREFIX_TIME_LOCK, hash));
105:
106: assembly {
107: sstore(key, eta)
108: }
109: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Caller.sol#L11-L11
11: function _call(
12: address target,
13: bytes calldata callData,
14: uint256 nativeValue
15: ) internal {
16: if (nativeValue > address(this).balance) revert InsufficientBalance();
17:
18: (bool success, ) = target.call{ value: nativeValue }(callData);
19: if (!success) {
20: revert ExecutionFailed();
21: }
22: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L106-L106
106: function callContract(
107: string calldata destinationChain,
108: string calldata destinationContractAddress,
109: bytes calldata payload
110: ) external {
111: emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload);
112: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L114-L114
114: function callContractWithToken(
115: string calldata destinationChain,
116: string calldata destinationContractAddress,
117: bytes calldata payload,
118: string calldata symbol,
119: uint256 amount
120: ) external {
121: _burnTokenFrom(msg.sender, symbol, amount);
122: emit ContractCallWithToken(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload, symbol, amount);
123: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L125-L125
125: function isContractCallApproved(
126: bytes32 commandId,
127: string calldata sourceChain,
128: string calldata sourceAddress,
129: address contractAddress,
130: bytes32 payloadHash
131: ) external view override returns (bool) {
132: return getBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash));
133: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L135-L135
135: function isContractCallAndMintApproved(
136: bytes32 commandId,
137: string calldata sourceChain,
138: string calldata sourceAddress,
139: address contractAddress,
140: bytes32 payloadHash,
141: string calldata symbol,
142: uint256 amount
143: ) external view override returns (bool) {
144: return
145: getBool(
146: _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount)
147: );
148: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L150-L150
150: function validateContractCall(
151: bytes32 commandId,
152: string calldata sourceChain,
153: string calldata sourceAddress,
154: bytes32 payloadHash
155: ) external override returns (bool valid) {
156: bytes32 key = _getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash);
157: valid = getBool(key);
158: if (valid) _setBool(key, false);
159: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L161-L161
161: function validateContractCallAndMint(
162: bytes32 commandId,
163: string calldata sourceChain,
164: string calldata sourceAddress,
165: bytes32 payloadHash,
166: string calldata symbol,
167: uint256 amount
168: ) external override returns (bool valid) {
169: bytes32 key = _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash, symbol, amount);
170: valid = getBool(key);
171: if (valid) {
172:
173: _setBool(key, false);
174: _mintToken(symbol, msg.sender, amount);
175: }
176: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L241-L241
241: function isCommandExecuted(bytes32 commandId) public view override returns (bool) {
242: return getBool(_getIsCommandExecutedKey(commandId));
243: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L420-L420
420: function mintToken(bytes calldata params, bytes32) external onlySelf {
421: (string memory symbol, address account, uint256 amount) = abi.decode(params, (string, address, uint256));
422:
423: _mintToken(symbol, account, amount);
424: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L454-L454
454: function approveContractCall(bytes calldata params, bytes32 commandId) external onlySelf {
455: (
456: string memory sourceChain,
457: string memory sourceAddress,
458: address contractAddress,
459: bytes32 payloadHash,
460: bytes32 sourceTxHash,
461: uint256 sourceEventIndex
462: ) = abi.decode(params, (string, string, address, bytes32, bytes32, uint256));
463:
464: _setContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash);
465: emit ContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, sourceTxHash, sourceEventIndex);
466: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L468-L468
468: function approveContractCallWithMint(bytes calldata params, bytes32 commandId) external onlySelf {
469: (
470: string memory sourceChain,
471: string memory sourceAddress,
472: address contractAddress,
473: bytes32 payloadHash,
474: string memory symbol,
475: uint256 amount,
476: bytes32 sourceTxHash,
477: uint256 sourceEventIndex
478: ) = abi.decode(params, (string, string, address, bytes32, string, uint256, bytes32, uint256));
479:
480: _setContractCallApprovedWithMint(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount);
481: emit ContractCallApprovedWithMint(
482: commandId,
483: sourceChain,
484: sourceAddress,
485: contractAddress,
486: payloadHash,
487: symbol,
488: amount,
489: sourceTxHash,
490: sourceEventIndex
491: );
492: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L494-L494
494: function transferOperatorship(bytes calldata newOperatorsData, bytes32) external onlySelf {
495: IAxelarAuth(AUTH_MODULE).transferOperatorship(newOperatorsData);
496:
497: emit OperatorshipTransferred(newOperatorsData);
498: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L572-L572
572: function _getIsCommandExecutedKey(bytes32 commandId) internal pure returns (bytes32) {
573: return keccak256(abi.encodePacked(PREFIX_COMMAND_EXECUTED, commandId));
574: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L576-L576
576: function _getIsContractCallApprovedKey(
577: bytes32 commandId,
578: string memory sourceChain,
579: string memory sourceAddress,
580: address contractAddress,
581: bytes32 payloadHash
582: ) internal pure returns (bytes32) {
583: return keccak256(abi.encode(PREFIX_CONTRACT_CALL_APPROVED, commandId, sourceChain, sourceAddress, contractAddress, payloadHash));
584: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L586-L586
586: function _getIsContractCallApprovedWithMintKey(
587: bytes32 commandId,
588: string memory sourceChain,
589: string memory sourceAddress,
590: address contractAddress,
591: bytes32 payloadHash,
592: string memory symbol,
593: uint256 amount
594: ) internal pure returns (bytes32) {
595: return
596: keccak256(
597: abi.encode(
598: PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT,
599: commandId,
600: sourceChain,
601: sourceAddress,
602: contractAddress,
603: payloadHash,
604: symbol,
605: amount
606: )
607: );
608: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L614-L614
614: function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) {
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash)))));
616: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L647-L647
647: function _setCommandExecuted(bytes32 commandId, bool executed) internal {
648: _setBool(_getIsCommandExecutedKey(commandId), executed);
649: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L651-L651
651: function _setContractCallApproved(
652: bytes32 commandId,
653: string memory sourceChain,
654: string memory sourceAddress,
655: address contractAddress,
656: bytes32 payloadHash
657: ) internal {
658: _setBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash), true);
659: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L661-L661
661: function _setContractCallApprovedWithMint(
662: bytes32 commandId,
663: string memory sourceChain,
664: string memory sourceAddress,
665: address contractAddress,
666: bytes32 payloadHash,
667: string memory symbol,
668: uint256 amount
669: ) internal {
670: _setBool(
671: _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount),
672: true
673: );
674: }
41: function _execute(
42: string calldata sourceChain,
43: string calldata sourceAddress,
44: bytes calldata payload
45: ) internal override {
46: _beforeProposalExecuted(sourceChain, sourceAddress, payload);
47:
48:
49: if (!whitelistedSenders[sourceChain][StringToAddress.toAddress(sourceAddress)]) {
50: revert NotWhitelistedSourceAddress();
51: }
52:
53:
54: (address interchainProposalCaller, InterchainCalls.Call[] memory calls) = abi.decode(payload, (address, InterchainCalls.Call[]));
55:
56:
57: if (!whitelistedCallers[sourceChain][interchainProposalCaller]) {
58: revert NotWhitelistedCaller();
59: }
60:
61:
62: _executeProposal(calls);
63:
64: _onProposalExecuted(sourceChain, sourceAddress, interchainProposalCaller, payload);
65:
126: function _beforeProposalExecuted(
127: string calldata sourceChain,
128: string calldata sourceAddress,
129: bytes calldata payload
130: ) internal virtual {
131:
132: }
142: function _onProposalExecuted(
143: string calldata,
144: string calldata,
145: address,
146: bytes calldata payload
147: ) internal virtual {
148:
149: }
178: function _onTargetExecuted(InterchainCalls.Call memory call, bytes memory result) internal virtual {
179:
180: }
24: function deploy(bytes memory bytecode, bytes32 salt) external returns (address deployedAddress_) {
25: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt)));
26: }
42: function deployAndInit(
43: bytes memory bytecode,
44: bytes32 salt,
45: bytes calldata init
46: ) external returns (address deployedAddress_) {
47: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt)));
48:
49:
50: (bool success, ) = deployedAddress_.call(init);
51: if (!success) revert FailedInit();
52: }
58: function deployedAddress(
59: bytes calldata bytecode,
60: address sender,
61: bytes32 salt
62: ) external view returns (address deployedAddress_) {
63: bytes32 newSalt = keccak256(abi.encode(sender, salt));
64: deployedAddress_ = address(
65: uint160(
66: uint256(
67: keccak256(
68: abi.encodePacked(
69: hex'ff',
70: address(this),
71: newSalt,
72: keccak256(bytecode)
73: )
74: )
75: )
76: )
77: );
78: }
29: function deploy(bytes calldata bytecode, bytes32 salt) external returns (address deployedAddress_) {
30: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt));
31: deployedAddress_ = Create3.deploy(deploySalt, bytecode);
32:
33: emit Deployed(keccak256(bytecode), salt, deployedAddress_);
34: }
49: function deployAndInit(
50: bytes memory bytecode,
51: bytes32 salt,
52: bytes calldata init
53: ) external returns (address deployedAddress_) {
54: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt));
55: deployedAddress_ = Create3.deploy(deploySalt, bytecode);
56:
57: (bool success, ) = deployedAddress_.call(init);
58: if (!success) revert FailedInit();
59:
60: emit Deployed(keccak256(bytecode), salt, deployedAddress_);
61: }
67: function deployedAddress(address sender, bytes32 salt) external view returns (address) {
68: bytes32 deploySalt = keccak256(abi.encode(sender, salt));
69: return Create3.deployedAddress(address(this), deploySalt);
70: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L21-L21
21: function deploy(bytes memory bytecode) external {
22: address deployed;
23:
24: assembly {
25: deployed := create(0, add(bytecode, 32), mload(bytecode))
26: if iszero(deployed) {
27: revert(0, 0)
28: }
29: }
30: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L71-L71
71: function deployedAddress(address sender, bytes32 salt) internal pure returns (address deployed) {
72: address deployer = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', sender, salt, DEPLOYER_BYTECODE_HASH)))));
73:
74: deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01')))));
75: }
32: function setup(bytes calldata params) external {}
78: function setup(bytes calldata data) external override onlyProxy {
79: _setup(data);
80: }
87: function _setup(bytes calldata data) internal virtual {}
31: function setup(bytes calldata setupParams) external {}
43: function interchainTransfer(
44: string calldata destinationChain,
45: bytes calldata recipient,
46: uint256 amount,
47: bytes calldata metadata
48: ) external payable {
49: address sender = msg.sender;
50: ITokenManager tokenManager = getTokenManager();
51:
52:
53:
54: if (tokenManagerRequiresApproval()) {
55: uint256 allowance_ = allowance[sender][address(tokenManager)];
56: if (allowance_ != type(uint256).max) {
57: if (allowance_ > type(uint256).max - amount) {
58: allowance_ = type(uint256).max - amount;
59: }
60:
61: _approve(sender, address(tokenManager), allowance_ + amount);
62: }
63: }
64:
65:
66: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata);
67: }
79: function interchainTransferFrom(
80: address sender,
81: string calldata destinationChain,
82: bytes calldata recipient,
83: uint256 amount,
84: bytes calldata metadata
85: ) external payable {
86: uint256 _allowance = allowance[sender][msg.sender];
87:
88: if (_allowance != type(uint256).max) {
89: _approve(sender, msg.sender, _allowance - amount);
90: }
91:
92: ITokenManager tokenManager = getTokenManager();
93: if (tokenManagerRequiresApproval()) {
94: uint256 allowance_ = allowance[sender][address(tokenManager)];
95: if (allowance_ != type(uint256).max) {
96: if (allowance_ > type(uint256).max - amount) {
97: allowance_ = type(uint256).max - amount;
98: }
99:
100: _approve(sender, address(tokenManager), allowance_ + amount);
101: }
102: }
103:
161: function getTokenManagerAddress(bytes32 tokenId) public view returns (address tokenManagerAddress) {
162: tokenManagerAddress = deployer.deployedAddress(address(this), tokenId);
163: }
170: function getValidTokenManagerAddress(bytes32 tokenId) public view returns (address tokenManagerAddress) {
171: tokenManagerAddress = getTokenManagerAddress(tokenId);
172: if (ITokenManagerProxy(tokenManagerAddress).tokenId() != tokenId) revert TokenManagerDoesNotExist(tokenId);
173: }
180: function getTokenAddress(bytes32 tokenId) external view returns (address tokenAddress) {
181: address tokenManagerAddress = getValidTokenManagerAddress(tokenId);
182: tokenAddress = ITokenManager(tokenManagerAddress).tokenAddress();
183: }
191: function getStandardizedTokenAddress(bytes32 tokenId) public view returns (address tokenAddress) {
192: tokenId = _getStandardizedTokenSalt(tokenId);
193: tokenAddress = deployer.deployedAddress(address(this), tokenId);
194: }
213: function getCustomTokenId(address sender, bytes32 salt) public pure returns (bytes32 tokenId) {
214: tokenId = keccak256(abi.encode(PREFIX_CUSTOM_TOKEN_ID, sender, salt));
215: }
241: function getParamsLockUnlock(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) {
242: params = abi.encode(operator, tokenAddress);
243: }
251: function getParamsMintBurn(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) {
252: params = abi.encode(operator, tokenAddress);
253: }
262: function getParamsLiquidityPool(
263: bytes memory operator,
264: address tokenAddress,
265: address liquidityPoolAddress
266: ) public pure returns (bytes memory params) {
267: params = abi.encode(operator, tokenAddress, liquidityPoolAddress);
268: }
275: function getFlowLimit(bytes32 tokenId) external view returns (uint256 flowLimit) {
276: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
277: flowLimit = tokenManager.getFlowLimit();
278: }
285: function getFlowOutAmount(bytes32 tokenId) external view returns (uint256 flowOutAmount) {
286: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
287: flowOutAmount = tokenManager.getFlowOutAmount();
288: }
295: function getFlowInAmount(bytes32 tokenId) external view returns (uint256 flowInAmount) {
296: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
297: flowInAmount = tokenManager.getFlowInAmount();
298: }
325: function deployRemoteCanonicalToken(
326: bytes32 tokenId,
327: string calldata destinationChain,
328: uint256 gasValue
329: ) public payable notPaused {
330: address tokenAddress = getValidTokenManagerAddress(tokenId);
331: tokenAddress = ITokenManager(tokenAddress).tokenAddress();
332: if (getCanonicalTokenId(tokenAddress) != tokenId) revert NotCanonicalTokenManager();
333: (string memory tokenName, string memory tokenSymbol, uint8 tokenDecimals) = _validateToken(tokenAddress);
334: _deployRemoteStandardizedToken(tokenId, tokenName, tokenSymbol, tokenDecimals, '', '', destinationChain, gasValue);
335: }
343: function deployCustomTokenManager(
344: bytes32 salt,
345: TokenManagerType tokenManagerType,
346: bytes memory params
347: ) public payable notPaused returns (bytes32 tokenId) {
348: address deployer_ = msg.sender;
349: tokenId = getCustomTokenId(deployer_, salt);
350: _deployTokenManager(tokenId, tokenManagerType, params);
351: emit CustomTokenIdClaimed(tokenId, deployer_, salt);
352: }
365: function deployRemoteCustomTokenManager(
366: bytes32 salt,
367: string calldata destinationChain,
368: TokenManagerType tokenManagerType,
369: bytes calldata params,
370: uint256 gasValue
371: ) external payable notPaused returns (bytes32 tokenId) {
372: address deployer_ = msg.sender;
373: tokenId = getCustomTokenId(deployer_, salt);
374: _deployRemoteTokenManager(tokenId, destinationChain, gasValue, tokenManagerType, params);
375: emit CustomTokenIdClaimed(tokenId, deployer_, salt);
376: }
388: function deployAndRegisterStandardizedToken(
389: bytes32 salt,
390: string calldata name,
391: string calldata symbol,
392: uint8 decimals,
393: uint256 mintAmount,
394: address distributor
395: ) external payable notPaused {
396: bytes32 tokenId = getCustomTokenId(msg.sender, salt);
397: _deployStandardizedToken(tokenId, distributor, name, symbol, decimals, mintAmount, msg.sender);
398: address tokenManagerAddress = getTokenManagerAddress(tokenId);
399: TokenManagerType tokenManagerType = distributor == tokenManagerAddress ? TokenManagerType.MINT_BURN : TokenManagerType.LOCK_UNLOCK;
400: address tokenAddress = getStandardizedTokenAddress(tokenId);
401: _deployTokenManager(tokenId, tokenManagerType, abi.encode(msg.sender.toBytes(), tokenAddress));
402: }
417: function deployAndRegisterRemoteStandardizedToken(
418: bytes32 salt,
419: string calldata name,
420: string calldata symbol,
421: uint8 decimals,
422: bytes memory distributor,
423: bytes memory operator,
424: string calldata destinationChain,
425: uint256 gasValue
426: ) external payable notPaused {
427: bytes32 tokenId = getCustomTokenId(msg.sender, salt);
428: _deployRemoteStandardizedToken(tokenId, name, symbol, decimals, distributor, operator, destinationChain, gasValue);
429: }
439: function expressReceiveToken(
440: bytes32 tokenId,
441: address destinationAddress,
442: uint256 amount,
443: bytes32 commandId
444: ) external {
445: if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId);
446:
447: address caller = msg.sender;
448: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
449: IERC20 token = IERC20(tokenManager.tokenAddress());
450:
451: SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount);
452:
453: _setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, caller);
454: }
467: function expressReceiveTokenWithData(
468: bytes32 tokenId,
469: string memory sourceChain,
470: bytes memory sourceAddress,
471: address destinationAddress,
472: uint256 amount,
473: bytes calldata data,
474: bytes32 commandId
475: ) external {
476: if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId);
477:
478: address caller = msg.sender;
479: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
480: IERC20 token = IERC20(tokenManager.tokenAddress());
481:
482: SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount);
483:
484: _expressExecuteWithInterchainTokenToken(tokenId, destinationAddress, sourceChain, sourceAddress, data, amount);
485:
486: _setExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, caller);
487: }
555: function _setup(bytes calldata params) internal override {
556: _setOperator(params.toAddress());
557: }
575: function _execute(
576: string calldata sourceChain,
577: string calldata sourceAddress,
578: bytes calldata payload
579: ) internal override onlyRemoteService(sourceChain, sourceAddress) notPaused {
580: uint256 selector = abi.decode(payload, (uint256));
581: if (selector == SELECTOR_SEND_TOKEN) {
582: _processSendTokenPayload(sourceChain, payload);
583: } else if (selector == SELECTOR_SEND_TOKEN_WITH_DATA) {
584: _processSendTokenWithDataPayload(sourceChain, payload);
585: } else if (selector == SELECTOR_DEPLOY_TOKEN_MANAGER) {
586: _processDeployTokenManagerPayload(payload);
587: } else if (selector == SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN) {
588: _processDeployStandardizedTokenAndManagerPayload(payload);
589: } else {
590: revert SelectorUnknown();
591: }
592: }
599: function _processSendTokenPayload(string calldata sourceChain, bytes calldata payload) internal {
600: (, bytes32 tokenId, bytes memory destinationAddressBytes, uint256 amount) = abi.decode(payload, (uint256, bytes32, bytes, uint256));
601: bytes32 commandId;
602:
603: assembly {
604: commandId := calldataload(4)
605: }
606: address destinationAddress = destinationAddressBytes.toAddress();
607: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId));
608: address expressCaller = _popExpressReceiveToken(tokenId, destinationAddress, amount, commandId);
609: if (expressCaller == address(0)) {
610: amount = tokenManager.giveToken(destinationAddress, amount);
611: emit TokenReceived(tokenId, sourceChain, destinationAddress, amount);
612: } else {
613: amount = tokenManager.giveToken(expressCaller, amount);
614: }
615: }
622: function _processSendTokenWithDataPayload(string calldata sourceChain, bytes calldata payload) internal {
623: bytes32 tokenId;
624: uint256 amount;
625: bytes memory sourceAddress;
626: bytes memory data;
627: address destinationAddress;
628: bytes32 commandId;
629:
630: assembly {
631: commandId := calldataload(4)
632: }
633: {
634: bytes memory destinationAddressBytes;
635: (, tokenId, destinationAddressBytes, amount, sourceAddress, data) = abi.decode(
636: payload,
637: (uint256, bytes32, bytes, uint256, bytes, bytes)
638: );
639: destinationAddress = destinationAddressBytes.toAddress();
640: }
641: ITokenManager tokenManager = ITokenManager(getTokenManagerAddress(tokenId));
642: {
643: address expressCaller = _popExpressReceiveTokenWithData(
644: tokenId,
645: sourceChain,
646: sourceAddress,
666: function _processDeployTokenManagerPayload(bytes calldata payload) internal {
667: (, bytes32 tokenId, TokenManagerType tokenManagerType, bytes memory params) = abi.decode(
668: payload,
669: (uint256, bytes32, TokenManagerType, bytes)
670: );
671: _deployTokenManager(tokenId, tokenManagerType, params);
672: }
707: function _callContract(
708: string calldata destinationChain,
709: bytes memory payload,
710: uint256 gasValue,
711: address refundTo
712: ) internal {
713: string memory destinationAddress = remoteAddressValidator.getRemoteAddress(destinationChain);
714: if (gasValue > 0) {
715: gasService.payNativeGasForContractCall{ value: gasValue }(
716: address(this),
717: destinationChain,
718: destinationAddress,
719: payload,
720: refundTo
721: );
722: }
723: gateway.callContract(destinationChain, destinationAddress, payload);
724: }
748: function _deployRemoteTokenManager(
749: bytes32 tokenId,
750: string calldata destinationChain,
751: uint256 gasValue,
752: TokenManagerType tokenManagerType,
753: bytes memory params
754: ) internal {
755: bytes memory payload = abi.encode(SELECTOR_DEPLOY_TOKEN_MANAGER, tokenId, tokenManagerType, params);
756: _callContract(destinationChain, payload, gasValue, msg.sender);
757: emit RemoteTokenManagerDeploymentInitialized(tokenId, destinationChain, gasValue, tokenManagerType, params);
758: }
770: function _deployRemoteStandardizedToken(
771: bytes32 tokenId,
772: string memory name,
773: string memory symbol,
774: uint8 decimals,
775: bytes memory distributor,
776: bytes memory operator,
777: string calldata destinationChain,
778: uint256 gasValue
779: ) internal {
780: bytes memory payload = abi.encode(
781: SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN,
782: tokenId,
783: name,
784: symbol,
785: decimals,
786: distributor,
787: operator
788: );
789: _callContract(destinationChain, payload, gasValue, msg.sender);
790: emit RemoteStandardizedTokenAndManagerDeploymentInitialized(
791: tokenId,
792: name,
793: symbol,
794: decimals,
808: function _deployTokenManager(
809: bytes32 tokenId,
810: TokenManagerType tokenManagerType,
811: bytes memory params
812: ) internal {
813: (bool success, ) = tokenManagerDeployer.delegatecall(
814: abi.encodeWithSelector(ITokenManagerDeployer.deployTokenManager.selector, tokenId, tokenManagerType, params)
815: );
816: if (!success) {
817: revert TokenManagerDeploymentFailed();
818: }
819: emit TokenManagerDeployed(tokenId, tokenManagerType, params);
820: }
827: function _getStandardizedTokenSalt(bytes32 tokenId) internal pure returns (bytes32 salt) {
828: return keccak256(abi.encode(PREFIX_STANDARDIZED_TOKEN_SALT, tokenId));
829: }
841: function _deployStandardizedToken(
842: bytes32 tokenId,
843: address distributor,
844: string memory name,
845: string memory symbol,
846: uint8 decimals,
847: uint256 mintAmount,
848: address mintTo
849: ) internal {
850: bytes32 salt = _getStandardizedTokenSalt(tokenId);
851: address tokenManagerAddress = getTokenManagerAddress(tokenId);
852:
853: (bool success, ) = standardizedTokenDeployer.delegatecall(
854: abi.encodeWithSelector(
855: IStandardizedTokenDeployer.deployStandardizedToken.selector,
856: salt,
857: tokenManagerAddress,
858: distributor,
859: name,
860: symbol,
861: decimals,
862: mintAmount,
863: mintTo
864: )
865: );
880: function _expressExecuteWithInterchainTokenToken(
881: bytes32 tokenId,
882: address destinationAddress,
883: string memory sourceChain,
884: bytes memory sourceAddress,
885: bytes calldata data,
886: uint256 amount
887: ) internal {
888: IInterchainTokenExpressExecutable(destinationAddress).expressExecuteWithInterchainToken(
889: sourceChain,
890: sourceAddress,
891: data,
892: tokenId,
893: amount
894: );
895: }
49: function setup(bytes calldata params) external override onlyProxy {
50: {
51: address distributor_;
52: address tokenManager_;
53: string memory tokenName;
54: (tokenManager_, distributor_, tokenName, symbol, decimals) = abi.decode(params, (address, address, string, string, uint8));
55: _setDistributor(distributor_);
56: tokenManager = tokenManager_;
57: _setDomainTypeSignatureHash(tokenName);
58: name = tokenName;
59: }
60: {
61: uint256 mintAmount;
62: address mintTo;
63: (, , , , , mintAmount, mintTo) = abi.decode(params, (address, address, string, string, uint8, uint256, address));
64: if (mintAmount > 0) {
65: _mint(mintTo, mintAmount);
66: }
67: }
68: }
83: function sendToken(
84: string calldata destinationChain,
85: bytes calldata destinationAddress,
86: uint256 amount,
87: bytes calldata metadata
88: ) external payable virtual {
89: address sender = msg.sender;
90: amount = _takeToken(sender, amount);
91: _addFlowOut(amount);
92: interchainTokenService.transmitSendToken{ value: msg.value }(
93: _getTokenId(),
94: sender,
95: destinationChain,
96: destinationAddress,
97: amount,
98: metadata
99: );
100: }
109: function callContractWithInterchainToken(
110: string calldata destinationChain,
111: bytes calldata destinationAddress,
112: uint256 amount,
113: bytes calldata data
114: ) external payable virtual {
115: address sender = msg.sender;
116: amount = _takeToken(sender, amount);
117: _addFlowOut(amount);
118: uint32 version = 0;
119: interchainTokenService.transmitSendToken{ value: msg.value }(
120: _getTokenId(),
121: sender,
122: destinationChain,
123: destinationAddress,
124: amount,
125: abi.encodePacked(version, data)
126: );
127: }
136: function transmitInterchainTransfer(
137: address sender,
138: string calldata destinationChain,
139: bytes calldata destinationAddress,
140: uint256 amount,
141: bytes calldata metadata
142: ) external payable virtual onlyToken {
143: amount = _takeToken(sender, amount);
144: _addFlowOut(amount);
145: interchainTokenService.transmitSendToken{ value: msg.value }(
146: _getTokenId(),
147: sender,
148: destinationChain,
149: destinationAddress,
150: amount,
151: metadata
152: );
153: }
32: function _setup(bytes calldata params) internal override {
33:
34: (, address tokenAddress) = abi.decode(params, (bytes, address));
35: _setTokenAddress(tokenAddress);
36: }
36: function _setup(bytes calldata params) internal override {
37:
38: (, address tokenAddress_, address liquidityPool_) = abi.decode(params, (bytes, address, address));
39: _setTokenAddress(tokenAddress_);
40: _setLiquidityPool(liquidityPool_);
41: }
26: function _getExpressReceiveTokenSlot(
27: bytes32 tokenId,
28: address destinationAddress,
29: uint256 amount,
30: bytes32 commandId
31: ) internal pure returns (uint256 slot) {
32: slot = uint256(keccak256(abi.encode(PREFIX_EXPRESS_RECEIVE_TOKEN, tokenId, destinationAddress, amount, commandId)));
33: }
46: function _getExpressReceiveTokenWithDataSlot(
47: bytes32 tokenId,
48: string memory sourceChain,
49: bytes memory sourceAddress,
50: address destinationAddress,
51: uint256 amount,
52: bytes memory data,
53: bytes32 commandId
54: ) internal pure returns (uint256 slot) {
55: slot = uint256(
56: keccak256(
57: abi.encode(
58: PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA,
59: tokenId,
60: sourceChain,
61: sourceAddress,
62: destinationAddress,
63: amount,
64: data,
65: commandId
66: )
67: )
68: );
69: }
79: function _setExpressReceiveToken(
80: bytes32 tokenId,
81: address destinationAddress,
82: uint256 amount,
83: bytes32 commandId,
84: address expressCaller
85: ) internal {
86: uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId);
87: address prevExpressCaller;
88: assembly {
89: prevExpressCaller := sload(slot)
90: }
91: if (prevExpressCaller != address(0)) revert AlreadyExpressCalled();
92: assembly {
93: sstore(slot, expressCaller)
94: }
95: emit ExpressReceive(tokenId, destinationAddress, amount, commandId, expressCaller);
96: }
110: function _setExpressReceiveTokenWithData(
111: bytes32 tokenId,
112: string memory sourceChain,
113: bytes memory sourceAddress,
114: address destinationAddress,
115: uint256 amount,
116: bytes calldata data,
117: bytes32 commandId,
118: address expressCaller
119: ) internal {
120: uint256 slot = _getExpressReceiveTokenWithDataSlot(
121: tokenId,
122: sourceChain,
123: sourceAddress,
124: destinationAddress,
125: amount,
126: data,
127: commandId
128: );
129: address prevExpressCaller;
130: assembly {
131: prevExpressCaller := sload(slot)
132: }
133: if (prevExpressCaller != address(0)) revert AlreadyExpressCalled();
134: assembly {
148: function getExpressReceiveToken(
149: bytes32 tokenId,
150: address destinationAddress,
151: uint256 amount,
152: bytes32 commandId
153: ) public view returns (address expressCaller) {
154: uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId);
155: assembly {
156: expressCaller := sload(slot)
157: }
158: }
171: function getExpressReceiveTokenWithData(
172: bytes32 tokenId,
173: string memory sourceChain,
174: bytes memory sourceAddress,
175: address destinationAddress,
176: uint256 amount,
177: bytes calldata data,
178: bytes32 commandId
179: ) public view returns (address expressCaller) {
180: uint256 slot = _getExpressReceiveTokenWithDataSlot(
181: tokenId,
182: sourceChain,
183: sourceAddress,
184: destinationAddress,
185: amount,
186: data,
187: commandId
188: );
189: assembly {
190: expressCaller := sload(slot)
191: }
192: }
202: function _popExpressReceiveToken(
203: bytes32 tokenId,
204: address destinationAddress,
205: uint256 amount,
206: bytes32 commandId
207: ) internal returns (address expressCaller) {
208: uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId);
209: assembly {
210: expressCaller := sload(slot)
211: }
212: if (expressCaller != address(0)) {
213: assembly {
214: sstore(slot, 0)
215: }
216: emit ExpressExecutionFulfilled(tokenId, destinationAddress, amount, commandId, expressCaller);
217: }
218: }
231: function _popExpressReceiveTokenWithData(
232: bytes32 tokenId,
233: string memory sourceChain,
234: bytes memory sourceAddress,
235: address destinationAddress,
236: uint256 amount,
237: bytes memory data,
238: bytes32 commandId
239: ) internal returns (address expressCaller) {
240: uint256 slot = _getExpressReceiveTokenWithDataSlot(
241: tokenId,
242: sourceChain,
243: sourceAddress,
244: destinationAddress,
245: amount,
246: data,
247: commandId
248: );
249: assembly {
250: expressCaller := sload(slot)
251: }
252: if (expressCaller != address(0)) {
253: assembly {
254: sstore(slot, 0)
255: }
2
It's often considered a good practice to use a timelock on sensitive functions such as upgrading a contract, especially when these contracts handle user funds or critical system states.
A timelock is a delay period that must pass between when an action (like an upgrade) is scheduled and when it can be executed. This provides a window of time for users or governance participants to observe the proposed change and potentially respond if they disagree with the action.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L279-L279
279: function upgrade( // <= FOUND
280: address newImplementation,
281: bytes32 newImplementationCodeHash,
282: bytes calldata setupParams
283: ) external override onlyGovernance {
284: if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();
285:
286: if (AxelarGateway(newImplementation).contractId() != contractId()) revert InvalidImplementation();
287:
288: emit Upgraded(newImplementation);
289:
290:
291:
292: if (setupParams.length != 0) {
293: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(IAxelarGateway.setup.selector, setupParams));
294:
295: if (!success) revert SetupFailed();
296: }
297:
298: _setImplementation(newImplementation);
299: }
52: function upgrade( // <= FOUND
53: address newImplementation,
54: bytes32 newImplementationCodeHash,
55: bytes calldata params
56: ) external override onlyOwner {
57: if (IUpgradable(newImplementation).contractId() != IUpgradable(this).contractId()) revert InvalidImplementation();
58: if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();
59:
60: if (params.length > 0) {
61: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params));
62:
63: if (!success) revert SetupFailed();
64: }
65:
66: emit Upgraded(newImplementation);
67:
68: assembly {
69: sstore(_IMPLEMENTATION_SLOT, newImplementation)
70: }
71: }
[GAS-1] The use of a logical AND in place of double if is slightly less gas efficient in instances where there isn't a corresponding else statement for the given if statement
5
Using a double if statement instead of logical AND (&&) can provide similar short-circuiting behavior whereas double if is slightly more efficient.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L445-L445
426: function burnToken(bytes calldata params, bytes32) external onlySelf {
427: (string memory symbol, bytes32 salt) = abi.decode(params, (string, bytes32));
428:
429: address tokenAddress = tokenAddresses(symbol);
430:
431: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
432:
433: if (_getTokenType(symbol) == TokenType.External) {
434: address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode)));
435:
436: if (_hasCode(depositHandlerAddress)) return;
437:
438: DepositHandler depositHandler = new DepositHandler{ salt: salt }();
439:
440: (bool success, bytes memory returnData) = depositHandler.execute(
441: tokenAddress,
442: abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler)))
443: );
444:
445: if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol); // <= FOUND
446:
447:
448: depositHandler.destroy(address(this));
449: } else {
450: IBurnableMintableCappedERC20(tokenAddress).burn(salt);
451: }
452: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L508-L508
504: function _hasCode(address addr) internal view returns (bool) {
505: bytes32 codehash = addr.codehash;
506:
507:
508: return codehash != bytes32(0) && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // <= FOUND
509: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L634-L634
632: function _setTokenMintAmount(string memory symbol, uint256 amount) internal {
633: uint256 limit = tokenMintLimit(symbol);
634: if (limit > 0 && amount > limit) revert ExceedMintLimit(symbol); // <= FOUND
635:
636: _setUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours), amount);
637: }
35: function init(
36: address implementationAddress,
37: address newOwner,
38: bytes memory params
39: ) external {
40: address owner;
41:
42: assembly {
43: owner := sload(_OWNER_SLOT)
44: }
45:
46: if (msg.sender != owner) revert NotOwner();
47: if (implementation() != address(0)) revert AlreadyInitialized();
48:
49: bytes32 id = contractId();
50: if (id != bytes32(0) && IUpgradable(implementationAddress).contractId() != id) revert InvalidImplementation(); // <= FOUND
51:
52: assembly {
53: sstore(_IMPLEMENTATION_SLOT, implementationAddress)
54: sstore(_OWNER_SLOT, newOwner)
55: }
56:
57: if (params.length != 0) {
58: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IUpgradable.setup.selector, params));
59: if (!success) revert SetupFailed();
60: }
61: }
54: function _lowerCase(string memory s) internal pure returns (string memory) {
55: uint256 length = bytes(s).length;
56: for (uint256 i; i < length; i++) {
57: uint8 b = uint8(bytes(s)[i]);
58: if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32)); // <= FOUND
59: }
60: return s;
61: }
3
Rather than calling .length for an array in a for loop declaration, it is far more gas efficient to cache this length before and use that instead. This will prevent the array length from being called every loop iteration
Findings are labeled with ' <= FOUND'
Click to show findings
63: for (uint256 i = 0; i < interchainCalls.length; ) // <= FOUND
74: for (uint256 i = 0; i < calls.length; i++) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L24-L24
24: for (uint256 i = 0; i < data.length; ++i) // <= FOUND
3
Move the ++/-- action to the left of the variable
Findings are labeled with ' <= FOUND'
Click to show findings
73: function _executeProposal(InterchainCalls.Call[] memory calls) internal {
74: for (uint256 i = 0; i < calls.length; i++) { // <= FOUND
75: InterchainCalls.Call memory call = calls[i];
76: (bool success, bytes memory result) = call.target.call{ value: call.value }(call.callData);
77:
78: if (!success) {
79: _onTargetExecutionFailed(call, result);
80: } else {
81: _onTargetExecuted(call, result);
82: }
83: }
84: }
54: function _lowerCase(string memory s) internal pure returns (string memory) {
55: uint256 length = bytes(s).length;
56: for (uint256 i; i < length; i++) { // <= FOUND
57: uint8 b = uint8(bytes(s)[i]);
58: if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32));
59: }
60: return s;
61: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L124-L124
119: function getSignerVotesCount(bytes32 topic) external view override returns (uint256) {
120: uint256 length = signers.accounts.length;
121: uint256 voteCount;
122: for (uint256 i; i < length; ++i) {
123: if (votingPerTopic[signerEpoch][topic].hasVoted[signers.accounts[i]]) {
124: voteCount++; // <= FOUND
125: }
126: }
127:
128: return voteCount;
129: }
4
Internal functions which are never used use unnecessary gas and should be safely removed.
Findings are labeled with ' <= FOUND'
Click to show findings
41: function _execute( // <= FOUND
42: string calldata sourceChain,
43: string calldata sourceAddress,
44: bytes calldata payload
45: ) internal override
575: function _execute( // <= FOUND
576: string calldata sourceChain,
577: string calldata sourceAddress,
578: bytes calldata payload
579: ) internal override onlyRemoteService(sourceChain, sourceAddress) notPaused
155: function _executeWithToken( // <= FOUND
156: string calldata,
157: string calldata,
158: bytes calldata,
159: string calldata,
160: uint256
161: ) internal pure override
559: function _sanitizeTokenManagerImplementation(address[] memory implementaions, TokenManagerType tokenManagerType) // <= FOUND
560: internal
561: pure
562: returns (address implementation)
563:
31
If a internal function is only used once it doesn't make sense to modularise it unless the function which does call the function would be overly long and complex otherwise
Findings are labeled with ' <= FOUND'
Click to show findings
113: function _processCommand( // <= FOUND
114: uint256 commandId,
115: address target,
116: bytes memory callData,
117: uint256 nativeValue,
118: uint256 eta
119: ) internal virtual
72: function _processCommand( // <= FOUND
73: uint256 commandId,
74: address target,
75: bytes memory callData,
76: uint256 nativeValue,
77: uint256 eta
78: ) internal override
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L149-L149
149: function _rotateSigners(address[] memory newAccounts, uint256 newThreshold) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L79-L79
79: function _finalizeTimeLock(bytes32 hash) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L504-L504
504: function _hasCode(address addr) internal view returns (bool) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L614-L614
614: function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L632-L632
632: function _setTokenMintAmount(string memory symbol, uint256 amount) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L651-L651
651: function _setContractCallApproved( // <= FOUND
652: bytes32 commandId,
653: string memory sourceChain,
654: string memory sourceAddress,
655: address contractAddress,
656: bytes32 payloadHash
657: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L661-L661
661: function _setContractCallApprovedWithMint( // <= FOUND
662: bytes32 commandId,
663: string memory sourceChain,
664: string memory sourceAddress,
665: address contractAddress,
666: bytes32 payloadHash,
667: string memory symbol,
668: uint256 amount
669: ) internal
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L676-L676
676: function _setImplementation(address newImplementation) internal // <= FOUND
73: function _executeProposal(InterchainCalls.Call[] memory calls) internal // <= FOUND
126: function _beforeProposalExecuted( // <= FOUND
127: string calldata sourceChain,
128: string calldata sourceAddress,
129: bytes calldata payload
130: ) internal virtual
142: function _onProposalExecuted( // <= FOUND
143: string calldata,
144: string calldata,
145: address,
146: bytes calldata payload
147: ) internal virtual
156: function _onTargetExecutionFailed( // <= FOUND
157: InterchainCalls.Call memory,
158: bytes memory result
159: ) internal virtual
178: function _onTargetExecuted(InterchainCalls.Call memory call, bytes memory result) internal virtual // <= FOUND
599: function _processSendTokenPayload(string calldata sourceChain, bytes calldata payload) internal // <= FOUND
622: function _processSendTokenWithDataPayload(string calldata sourceChain, bytes calldata payload) internal // <= FOUND
666: function _processDeployTokenManagerPayload(bytes calldata payload) internal // <= FOUND
678: function _processDeployStandardizedTokenAndManagerPayload(bytes calldata payload) internal // <= FOUND
748: function _deployRemoteTokenManager( // <= FOUND
749: bytes32 tokenId,
750: string calldata destinationChain,
751: uint256 gasValue,
752: TokenManagerType tokenManagerType,
753: bytes memory params
754: ) internal
872: function _decodeMetadata(bytes calldata metadata) internal pure returns (uint32 version, bytes calldata data) // <= FOUND
880: function _expressExecuteWithInterchainTokenToken( // <= FOUND
881: bytes32 tokenId,
882: address destinationAddress,
883: string memory sourceChain,
884: bytes memory sourceAddress,
885: bytes calldata data,
886: uint256 amount
887: ) internal
54: function _getImplementation(IInterchainTokenService interchainTokenServiceAddress_, uint256 implementationType_) // <= FOUND
55: internal
56: view
57: returns (address impl)
58:
60: function _giveToken(address to, uint256 amount) internal override returns (uint256) // <= FOUND
79: function _setExpressReceiveToken( // <= FOUND
80: bytes32 tokenId,
81: address destinationAddress,
82: uint256 amount,
83: bytes32 commandId,
84: address expressCaller
85: ) internal
110: function _setExpressReceiveTokenWithData( // <= FOUND
111: bytes32 tokenId,
112: string memory sourceChain,
113: bytes memory sourceAddress,
114: address destinationAddress,
115: uint256 amount,
116: bytes calldata data,
117: bytes32 commandId,
118: address expressCaller
119: ) internal
202: function _popExpressReceiveToken( // <= FOUND
203: bytes32 tokenId,
204: address destinationAddress,
205: uint256 amount,
206: bytes32 commandId
207: ) internal returns (address expressCaller)
231: function _popExpressReceiveTokenWithData( // <= FOUND
232: bytes32 tokenId,
233: string memory sourceChain,
234: bytes memory sourceAddress,
235: address destinationAddress,
236: uint256 amount,
237: bytes memory data,
238: bytes32 commandId
239: ) internal returns (address expressCaller)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L34-L34
34: function _setFlowLimit(uint256 flowLimit) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L124-L124
124: function _addFlowIn(uint256 flowInAmount) internal // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L41-L41
41: function _setPaused(bool paused) internal // <= FOUND
15
Public functions that aren't used internally in Solidity contracts should be made external to optimize gas usage and improve contract efficiency. External functions can only be called from outside the contract, and their arguments are directly read from the calldata, which is more gas-efficient than loading them into memory, as is the case for public functions. By using external visibility, developers can reduce gas consumption for external calls and ensure that the contract operates more cost-effectively for users. Moreover, setting the appropriate visibility level for functions also enhances code readability and maintainability, promoting a more secure and well-structured contract design.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L182-L182
182: function authModule() public view override returns (address) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L186-L186
186: function governance() public view override returns (address) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L190-L190
190: function mintLimiter() public view override returns (address) // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L194-L194
194: function tokenDeployer() public view returns (address) // <= FOUND
48: function isFinal() public view returns (bool) // <= FOUND
72: function finalUpgrade(bytes memory bytecode, bytes calldata setupParams) public returns (address finalImplementation_) // <= FOUND
152: function getChainName() public view returns (string memory name) // <= FOUND
241: function getParamsLockUnlock(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) // <= FOUND
251: function getParamsMintBurn(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) // <= FOUND
262: function getParamsLiquidityPool( // <= FOUND
263: bytes memory operator,
264: address tokenAddress,
265: address liquidityPoolAddress
266: ) public pure returns (bytes memory params)
325: function deployRemoteCanonicalToken( // <= FOUND
326: bytes32 tokenId,
327: string calldata destinationChain,
328: uint256 gasValue
329: ) public payable notPaused
343: function deployCustomTokenManager( // <= FOUND
344: bytes32 salt,
345: TokenManagerType tokenManagerType,
346: bytes memory params
347: ) public payable notPaused returns (bytes32 tokenId)
148: function getExpressReceiveToken( // <= FOUND
149: bytes32 tokenId,
150: address destinationAddress,
151: uint256 amount,
152: bytes32 commandId
153: ) public view returns (address expressCaller)
171: function getExpressReceiveTokenWithData( // <= FOUND
172: bytes32 tokenId,
173: string memory sourceChain,
174: bytes memory sourceAddress,
175: address destinationAddress,
176: uint256 amount,
177: bytes calldata data,
178: bytes32 commandId
179: ) public view returns (address expressCaller)
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L22-L22
22: function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) // <= FOUND
73
Solidity version 0.8.19 introduced a array of gas optimizations which make contracts which use it more efficient. Provided compatability it may be beneficial to upgrade to this version
Findings are labeled with ' <= FOUND'
Click to show findings
3: pragma solidity ^0.8.0;
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L3-L3
3: pragma solidity ^0.8.9;
3
Given concatenation is not going to be used for hashing bytes.concat is the preferred method to use as its more gas efficient
Findings are labeled with ' <= FOUND'
Click to show findings
109: function callContractWithInterchainToken(
110: string calldata destinationChain,
111: bytes calldata destinationAddress,
112: uint256 amount,
113: bytes calldata data
114: ) external payable virtual {
115: address sender = msg.sender;
116: amount = _takeToken(sender, amount);
117: _addFlowOut(amount);
118: uint32 version = 0;
119: interchainTokenService.transmitSendToken{ value: msg.value }(
120: _getTokenId(),
121: sender,
122: destinationChain,
123: destinationAddress,
124: amount,
125: abi.encodePacked(version, data) // <= FOUND
126: );
127: }
49: function deployStandardizedToken(
50: bytes32 salt,
51: address tokenManager,
52: address distributor,
53: string calldata name,
54: string calldata symbol,
55: uint8 decimals,
56: uint256 mintAmount,
57: address mintTo
58: ) external payable {
59: bytes memory bytecode;
60: address implementationAddress = distributor == tokenManager ? implementationMintBurnAddress : implementationLockUnlockAddress;
61: {
62: bytes memory params = abi.encode(tokenManager, distributor, name, symbol, decimals, mintAmount, mintTo);
63: bytecode = abi.encodePacked(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params)); // <= FOUND
64: }
65: address tokenAddress = deployer.deploy(bytecode, salt);
66: if (tokenAddress.code.length == 0) revert TokenDeploymentFailed();
67: }
33: function deployTokenManager(
34: bytes32 tokenId,
35: uint256 implementationType,
36: bytes calldata params
37: ) external payable {
38: bytes memory args = abi.encode(address(this), implementationType, tokenId, params);
39: bytes memory bytecode = abi.encodePacked(type(TokenManagerProxy).creationCode, args); // <= FOUND
40: address tokenManagerAddress = deployer.deploy(bytecode, tokenId);
41: if (tokenManagerAddress.code.length == 0) revert TokenManagerDeploymentFailed();
42: }
27
Findings are labeled with ' <= FOUND'
Click to show findings
33: constructor(
34: address gateway,
35: string memory governanceChain_,
36: string memory governanceAddress_,
37: uint256 minimumTimeDelay
38: ) AxelarExecutable(gateway) TimeLock(minimumTimeDelay) {
39: governanceChain = governanceChain_;
40: governanceAddress = governanceAddress_;
41: governanceChainHash = keccak256(bytes(governanceChain_));
42: governanceAddressHash = keccak256(bytes(governanceAddress_));
43: }
33: constructor(
34: address gateway,
35: string memory governanceChain,
36: string memory governanceAddress,
37: uint256 minimumTimeDelay,
38: address[] memory cosigners,
39: uint256 threshold
40: ) InterchainGovernance(gateway, governanceChain, governanceAddress, minimumTimeDelay) MultisigBase(cosigners, threshold) {}
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L35-L35
35: constructor(address[] memory accounts, uint256 threshold) {
36: _rotateSigners(accounts, threshold);
37: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L20-L20
20: constructor(address[] memory accounts, uint256 threshold) MultisigBase(accounts, threshold) {}
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L21-L21
21: constructor(uint256 minimumTimeDelay) {
22: _minimumTimeLockDelay = minimumTimeDelay;
23: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L64-L64
64: constructor(address authModule_, address tokenDeployerImplementation_) {
65: if (authModule_.code.length == 0) revert InvalidAuthModule();
66: if (tokenDeployerImplementation_.code.length == 0) revert InvalidTokenDeployer();
67:
68: AUTH_MODULE = authModule_;
69: TOKEN_DEPLOYER_IMPLEMENTATION = tokenDeployerImplementation_;
70: }
42: constructor(address _gateway, address _gasService) {
43: gateway = IAxelarGateway(_gateway);
44: gasService = IAxelarGasService(_gasService);
45: }
29: constructor(address _gateway, address _owner) AxelarExecutable(_gateway) {
30: _transferOwnership(_owner);
31: }
25: constructor(
26: address implementationAddress,
27: address owner,
28: bytes memory setupParams
29: ) {
30: if (owner == address(0)) revert InvalidOwner();
31:
32: bytes32 id = contractId();
33: if (id != bytes32(0) && IUpgradable(implementationAddress).contractId() != id) revert InvalidImplementation();
34:
35: assembly {
36: sstore(_IMPLEMENTATION_SLOT, implementationAddress)
37: sstore(_OWNER_SLOT, owner)
38: }
39:
40: if (setupParams.length != 0) {
41: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IUpgradable.setup.selector, setupParams));
42: if (!success) revert SetupFailed();
43: }
44: }
22: constructor() {
23: implementationAddress = address(this);
24: }
20: constructor() {
21: assembly {
22: sstore(_OWNER_SLOT, caller())
23: }
24: }
26: constructor(
27: address implementationAddress,
28: address owner,
29: bytes memory setupParams
30: ) Proxy(implementationAddress, owner, setupParams) {}
23: constructor(address implementationAddress) {
24: implementation = implementationAddress;
25: }
83: constructor(
84: address tokenManagerDeployer_,
85: address standardizedTokenDeployer_,
86: address gateway_,
87: address gasService_,
88: address remoteAddressValidator_,
89: address[] memory tokenManagerImplementations,
90: string memory chainName_
91: ) AxelarExecutable(gateway_) {
92: if (
93: remoteAddressValidator_ == address(0) ||
94: gasService_ == address(0) ||
95: tokenManagerDeployer_ == address(0) ||
96: standardizedTokenDeployer_ == address(0)
97: ) revert ZeroAddress();
98: remoteAddressValidator = IRemoteAddressValidator(remoteAddressValidator_);
99: gasService = IAxelarGasService(gasService_);
100: tokenManagerDeployer = tokenManagerDeployer_;
101: standardizedTokenDeployer = standardizedTokenDeployer_;
102: deployer = ITokenManagerDeployer(tokenManagerDeployer_).deployer();
103:
104: if (tokenManagerImplementations.length != uint256(type(TokenManagerType).max) + 1) revert LengthMismatch();
105:
106: implementationLockUnlock = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.LOCK_UNLOCK);
107: implementationMintBurn = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.MINT_BURN);
19: constructor(
20: address implementationAddress,
21: address owner,
22: address operator
23: ) FinalProxy(implementationAddress, owner, abi.encodePacked(operator)) {}
20: constructor(
21: address implementationAddress,
22: address owner,
23: bytes memory params
24: ) Proxy(implementationAddress, owner, params) {}
21: constructor(address implementationAddress, bytes memory params) FixedProxy(implementationAddress) {
22: if (IStandardizedToken(implementationAddress).contractId() != CONTRACT_ID) revert InvalidImplementation();
23:
24: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IStandardizedToken.setup.selector, params));
25: if (!success) revert SetupFailed();
26: }
25: constructor(
26: address interchainTokenServiceAddress_,
27: uint256 implementationType_,
28: bytes32 tokenId_,
29: bytes memory params
30: ) {
31: interchainTokenServiceAddress = IInterchainTokenService(interchainTokenServiceAddress_);
32: implementationType = implementationType_;
33: tokenId = tokenId_;
34: address impl = _getImplementation(IInterchainTokenService(interchainTokenServiceAddress_), implementationType_);
35:
36: (bool success, ) = impl.delegatecall(abi.encodeWithSelector(TokenManagerProxy.setup.selector, params));
37: if (!success) revert SetupFailed();
38: }
27: constructor(address _interchainTokenServiceAddress) {
28: if (_interchainTokenServiceAddress == address(0)) revert ZeroAddress();
29: interchainTokenServiceAddress = _interchainTokenServiceAddress;
30: interchainTokenServiceAddressHash = keccak256(bytes(_lowerCase(interchainTokenServiceAddress.toString())));
31: }
27: constructor(address interchainTokenService_) {
28: if (interchainTokenService_ == address(0)) revert TokenLinkerZeroAddress();
29: interchainTokenService = IInterchainTokenService(interchainTokenService_);
30: }
19: constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {}
22: constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {}
26: constructor(
27: address deployer_,
28: address implementationLockUnlockAddress_,
29: address implementationMintBurnAddress_
30: ) {
31: if (deployer_ == address(0) || implementationLockUnlockAddress_ == address(0) || implementationMintBurnAddress_ == address(0))
32: revert AddressZero();
33: deployer = Create3Deployer(deployer_);
34: implementationLockUnlockAddress = implementationLockUnlockAddress_;
35: implementationMintBurnAddress = implementationMintBurnAddress_;
36: }
22: constructor(address deployer_) {
23: if (deployer_ == address(0)) revert AddressZero();
24: deployer = Create3Deployer(deployer_);
25: }
14
When using a smaller int/uint type it first needs to be converted to it's 258 bit counterpart to be operated, this increases the gass cost and thus should be avoided. However it does make sense to use smaller int/uint values within structs provided you pack the struct properly.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L385-L385
384: function deployToken(bytes calldata params, bytes32) external onlySelf {
385: (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode( // <= FOUND
386: params,
387: (string, string, uint8, uint256, address, uint256)
388: );
389:
390:
391: if (tokenAddresses(symbol) != address(0)) revert TokenAlreadyExists(symbol);
392:
393: if (tokenAddress == address(0)) {
394:
395: bytes32 salt = keccak256(abi.encodePacked(symbol));
396:
397: (bool success, bytes memory data) = TOKEN_DEPLOYER_IMPLEMENTATION.delegatecall(
398: abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt)
399: );
400:
401: if (!success) revert TokenDeployFailed(symbol);
402:
403: tokenAddress = abi.decode(data, (address));
404:
405: _setTokenType(symbol, TokenType.InternalBurnableFrom);
406: } else {
407:
408: if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);
409:
325: function deployRemoteCanonicalToken(
326: bytes32 tokenId,
327: string calldata destinationChain,
328: uint256 gasValue
329: ) public payable notPaused {
330: address tokenAddress = getValidTokenManagerAddress(tokenId);
331: tokenAddress = ITokenManager(tokenAddress).tokenAddress();
332: if (getCanonicalTokenId(tokenAddress) != tokenId) revert NotCanonicalTokenManager();
333: (string memory tokenName, string memory tokenSymbol, uint8 tokenDecimals) = _validateToken(tokenAddress); // <= FOUND
334: _deployRemoteStandardizedToken(tokenId, tokenName, tokenSymbol, tokenDecimals, '', '', destinationChain, gasValue);
335: }
388: function deployAndRegisterStandardizedToken(
389: bytes32 salt,
390: string calldata name,
391: string calldata symbol,
392: uint8 decimals, // <= FOUND
393: uint256 mintAmount,
394: address distributor
395: ) external payable notPaused {
396: bytes32 tokenId = getCustomTokenId(msg.sender, salt);
397: _deployStandardizedToken(tokenId, distributor, name, symbol, decimals, mintAmount, msg.sender);
398: address tokenManagerAddress = getTokenManagerAddress(tokenId);
399: TokenManagerType tokenManagerType = distributor == tokenManagerAddress ? TokenManagerType.MINT_BURN : TokenManagerType.LOCK_UNLOCK;
400: address tokenAddress = getStandardizedTokenAddress(tokenId);
401: _deployTokenManager(tokenId, tokenManagerType, abi.encode(msg.sender.toBytes(), tokenAddress));
402: }
417: function deployAndRegisterRemoteStandardizedToken(
418: bytes32 salt,
419: string calldata name,
420: string calldata symbol,
421: uint8 decimals, // <= FOUND
422: bytes memory distributor,
423: bytes memory operator,
424: string calldata destinationChain,
425: uint256 gasValue
426: ) external payable notPaused {
427: bytes32 tokenId = getCustomTokenId(msg.sender, salt);
428: _deployRemoteStandardizedToken(tokenId, name, symbol, decimals, distributor, operator, destinationChain, gasValue);
429: }
678: function _processDeployStandardizedTokenAndManagerPayload(bytes calldata payload) internal {
679: (
680: ,
681: bytes32 tokenId,
682: string memory name,
683: string memory symbol,
684: uint8 decimals, // <= FOUND
685: bytes memory distributorBytes,
686: bytes memory operatorBytes
687: ) = abi.decode(payload, (uint256, bytes32, string, string, uint8, bytes, bytes));
688: address tokenAddress = getStandardizedTokenAddress(tokenId);
689: address tokenManagerAddress = getTokenManagerAddress(tokenId);
690: address distributor = distributorBytes.length > 0 ? distributorBytes.toAddress() : tokenManagerAddress;
691: _deployStandardizedToken(tokenId, distributor, name, symbol, decimals, 0, distributor);
692: TokenManagerType tokenManagerType = distributor == tokenManagerAddress ? TokenManagerType.MINT_BURN : TokenManagerType.LOCK_UNLOCK;
693: _deployTokenManager(
694: tokenId,
695: tokenManagerType,
696: abi.encode(operatorBytes.length == 0 ? address(this).toBytes() : operatorBytes, tokenAddress)
697: );
698: }
726: function _validateToken(address tokenAddress)
727: internal
728: returns (
729: string memory name,
730: string memory symbol,
731: uint8 decimals // <= FOUND
732: )
733: {
734: IERC20Named token = IERC20Named(tokenAddress);
735: name = token.name();
736: symbol = token.symbol();
737: decimals = token.decimals();
738: }
770: function _deployRemoteStandardizedToken(
771: bytes32 tokenId,
772: string memory name,
773: string memory symbol,
774: uint8 decimals, // <= FOUND
775: bytes memory distributor,
776: bytes memory operator,
777: string calldata destinationChain,
778: uint256 gasValue
779: ) internal {
780: bytes memory payload = abi.encode(
781: SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN,
782: tokenId,
783: name,
784: symbol,
785: decimals,
786: distributor,
787: operator
788: );
789: _callContract(destinationChain, payload, gasValue, msg.sender);
790: emit RemoteStandardizedTokenAndManagerDeploymentInitialized(
791: tokenId,
792: name,
793: symbol,
794: decimals,
795: distributor,
796: operator,
797: destinationChain,
798: gasValue
841: function _deployStandardizedToken(
842: bytes32 tokenId,
843: address distributor,
844: string memory name,
845: string memory symbol,
846: uint8 decimals, // <= FOUND
847: uint256 mintAmount,
848: address mintTo
849: ) internal {
850: bytes32 salt = _getStandardizedTokenSalt(tokenId);
851: address tokenManagerAddress = getTokenManagerAddress(tokenId);
852:
853: (bool success, ) = standardizedTokenDeployer.delegatecall(
854: abi.encodeWithSelector(
855: IStandardizedTokenDeployer.deployStandardizedToken.selector,
856: salt,
857: tokenManagerAddress,
858: distributor,
859: name,
860: symbol,
861: decimals,
862: mintAmount,
863: mintTo
864: )
865: );
866: if (!success) {
867: revert StandardizedTokenDeploymentFailed();
868: }
869: emit StandardizedTokenDeployed(tokenId, name, symbol, decimals, mintAmount, mintTo);
870: }
54: function _lowerCase(string memory s) internal pure returns (string memory) {
55: uint256 length = bytes(s).length;
56: for (uint256 i; i < length; i++) {
57: uint8 b = uint8(bytes(s)[i]); // <= FOUND
58: if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32));
59: }
60: return s;
61: }
49: function deployStandardizedToken(
50: bytes32 salt,
51: address tokenManager,
52: address distributor,
53: string calldata name,
54: string calldata symbol,
55: uint8 decimals, // <= FOUND
56: uint256 mintAmount,
57: address mintTo
58: ) external payable {
59: bytes memory bytecode;
60: address implementationAddress = distributor == tokenManager ? implementationMintBurnAddress : implementationLockUnlockAddress;
61: {
62: bytes memory params = abi.encode(tokenManager, distributor, name, symbol, decimals, mintAmount, mintTo);
63: bytecode = abi.encodePacked(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params));
64: }
65: address tokenAddress = deployer.deploy(bytecode, salt);
66: if (tokenAddress.code.length == 0) revert TokenDeploymentFailed();
67: }
25: uint8 public decimals; // <= FOUND
502: function transmitSendToken(
503: bytes32 tokenId,
504: address sourceAddress,
505: string calldata destinationChain,
506: bytes memory destinationAddress,
507: uint256 amount,
508: bytes calldata metadata
509: ) external payable onlyTokenManager(tokenId) notPaused {
510: bytes memory payload;
511: if (metadata.length < 4) {
512: payload = abi.encode(SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount);
513: _callContract(destinationChain, payload, msg.value, sourceAddress);
514: emit TokenSent(tokenId, destinationChain, destinationAddress, amount);
515: return;
516: }
517: uint32 version; // <= FOUND
518: (version, metadata) = _decodeMetadata(metadata);
519: if (version > 0) revert InvalidMetadataVersion(version);
520: payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata);
521: _callContract(destinationChain, payload, msg.value, sourceAddress);
522: emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata);
523: }
872: function _decodeMetadata(bytes calldata metadata) internal pure returns (uint32 version, bytes calldata data) { // <= FOUND
873: assembly {
874: data.length := sub(metadata.length, 4)
875: data.offset := add(metadata.offset, 4)
876: version := calldataload(sub(metadata.offset, 28))
877: }
878: }
109: function callContractWithInterchainToken(
110: string calldata destinationChain,
111: bytes calldata destinationAddress,
112: uint256 amount,
113: bytes calldata data
114: ) external payable virtual {
115: address sender = msg.sender;
116: amount = _takeToken(sender, amount);
117: _addFlowOut(amount);
118: uint32 version = 0; // <= FOUND
119: interchainTokenService.transmitSendToken{ value: msg.value }(
120: _getTokenId(),
121: sender,
122: destinationChain,
123: destinationAddress,
124: amount,
125: abi.encodePacked(version, data)
126: );
127: }
32
In Solidity, manipulating contract storage comes with significant gas costs. One can optimize gas usage by preventing unnecessary storage updates when the new value is the same as the existing one. If an existing value is the same as the new one, not reassigning it to the storage could potentially save substantial amounts of gas, notably 2900 gas for a 'Gsreset'. This saving may come at the expense of a cold storage load operation ('Gcoldsload'), which costs 2100 gas, or a warm storage access operation ('Gwarmaccess'), which costs 100 gas. Therefore, the gas efficiency of your contract can be significantly improved by adding a check that compares the new value with the current one before any storage update operation. If the values are the same, you can bypass the storage operation, thereby saving gas.
Findings are labeled with ' <= FOUND'
Click to show findings
92: function setWhitelistedProposalCaller(
93: string calldata sourceChain,
94: address sourceCaller,
95: bool whitelisted
96: ) external override onlyOwner {
97: whitelistedCallers[sourceChain][sourceCaller] = whitelisted;
98: emit WhitelistedProposalCallerSet(sourceChain, sourceCaller, whitelisted);
99: }
107: function setWhitelistedProposalSender(
108: string calldata sourceChain,
109: address sourceSender,
110: bool whitelisted
111: ) external override onlyOwner {
112: whitelistedSenders[sourceChain][sourceSender] = whitelisted;
113: emit WhitelistedProposalSenderSet(sourceChain, sourceSender, whitelisted);
114: }
32: function setup(bytes calldata params) external {}
78: function setup(bytes calldata data) external override onlyProxy {
79: _setup(data);
80: }
31: function setup(bytes calldata setupParams) external {}
547: function setPaused(bool paused) external onlyOwner {
548: _setPaused(paused);
549: }
49: function setup(bytes calldata params) external override onlyProxy {
50: {
51: address distributor_;
52: address tokenManager_;
53: string memory tokenName;
54: (tokenManager_, distributor_, tokenName, symbol, decimals) = abi.decode(params, (address, address, string, string, uint8));
55: _setDistributor(distributor_);
56: tokenManager = tokenManager_;
57: _setDomainTypeSignatureHash(tokenName);
58: name = tokenName;
59: }
60: {
61: uint256 mintAmount;
62: address mintTo;
63: (, , , , , mintAmount, mintTo) = abi.decode(params, (address, address, string, string, uint8, uint256, address));
64: if (mintAmount > 0) {
65: _mint(mintTo, mintAmount);
66: }
67: }
68: }
171: function setFlowLimit(uint256 flowLimit) external onlyOperator {
172: _setFlowLimit(flowLimit);
173: }
67: function setLiquidityPool(address newLiquidityPool) external onlyOperator {
68: _setLiquidityPool(newLiquidityPool);
69: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L51-L51
51: function setDistributor(address distr) external onlyDistributor {
52: _setDistributor(distr);
53: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L51-L51
51: function setOperator(address operator_) external onlyOperator {
52: _setOperator(operator_);
53: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L103-L103
103: function _setTimeLockEta(bytes32 hash, uint256 eta) private {
104: bytes32 key = keccak256(abi.encodePacked(PREFIX_TIME_LOCK, hash));
105:
106: assembly {
107: sstore(key, eta)
108: }
109: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L626-L626
626: function _setTokenMintLimit(string memory symbol, uint256 limit) internal {
627: _setUint(_getTokenMintLimitKey(symbol), limit);
628:
629: emit TokenMintLimitUpdated(symbol, limit);
630: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L632-L632
632: function _setTokenMintAmount(string memory symbol, uint256 amount) internal {
633: uint256 limit = tokenMintLimit(symbol);
634: if (limit > 0 && amount > limit) revert ExceedMintLimit(symbol);
635:
636: _setUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours), amount);
637: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L639-L639
639: function _setTokenType(string memory symbol, TokenType tokenType) internal {
640: _setUint(_getTokenTypeKey(symbol), uint256(tokenType));
641: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L643-L643
643: function _setTokenAddress(string memory symbol, address tokenAddress) internal {
644: _setAddress(_getTokenAddressKey(symbol), tokenAddress);
645: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L647-L647
647: function _setCommandExecuted(bytes32 commandId, bool executed) internal {
648: _setBool(_getIsCommandExecutedKey(commandId), executed);
649: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L651-L651
651: function _setContractCallApproved(
652: bytes32 commandId,
653: string memory sourceChain,
654: string memory sourceAddress,
655: address contractAddress,
656: bytes32 payloadHash
657: ) internal {
658: _setBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash), true);
659: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L661-L661
661: function _setContractCallApprovedWithMint(
662: bytes32 commandId,
663: string memory sourceChain,
664: string memory sourceAddress,
665: address contractAddress,
666: bytes32 payloadHash,
667: string memory symbol,
668: uint256 amount
669: ) internal {
670: _setBool(
671: _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount),
672: true
673: );
674: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L676-L676
676: function _setImplementation(address newImplementation) internal {
677: _setAddress(KEY_IMPLEMENTATION, newImplementation);
678: }
87: function _setup(bytes calldata data) internal virtual {}
555: function _setup(bytes calldata params) internal override {
556: _setOperator(params.toAddress());
557: }
38: function _setTokenAddress(address tokenAddress_) internal {
39: assembly {
40: sstore(TOKEN_ADDRESS_SLOT, tokenAddress_)
41: }
42: }
32: function _setup(bytes calldata params) internal override {
33:
34: (, address tokenAddress) = abi.decode(params, (bytes, address));
35: _setTokenAddress(tokenAddress);
36: }
36: function _setup(bytes calldata params) internal override {
37:
38: (, address tokenAddress_, address liquidityPool_) = abi.decode(params, (bytes, address, address));
39: _setTokenAddress(tokenAddress_);
40: _setLiquidityPool(liquidityPool_);
41: }
47: function _setLiquidityPool(address liquidityPool_) internal {
48: assembly {
49: sstore(LIQUIDITY_POOL_SLOT, liquidityPool_)
50: }
51: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L39-L39
39: function _setDistributor(address distributor_) internal {
40: assembly {
41: sstore(DISTRIBUTOR_SLOT, distributor_)
42: }
43: emit DistributorChanged(distributor_);
44: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L34-L34
34: function _setFlowLimit(uint256 flowLimit) internal {
35: assembly {
36: sstore(FLOW_LIMIT_SLOT, flowLimit)
37: }
38: emit FlowLimitSet(flowLimit);
39: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L39-L39
39: function _setOperator(address operator_) internal {
40: assembly {
41: sstore(OPERATOR_SLOT, operator_)
42: }
43: emit OperatorChanged(operator_);
44: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L41-L41
41: function _setPaused(bool paused) internal {
42: assembly {
43: sstore(PAUSE_SLOT, paused)
44: }
45:
46: emit PausedSet(paused);
47: }
8
Replace spotted instances with != 0 for uints as this uses less gas
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L634-L634
632: function _setTokenMintAmount(string memory symbol, uint256 amount) internal {
633: uint256 limit = tokenMintLimit(symbol);
634: if (limit > 0 && amount > limit) revert ExceedMintLimit(symbol); // <= FOUND
635:
636: _setUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours), amount);
637: }
88: function _sendProposal(InterchainCalls.InterchainCall memory interchainCall) internal {
89: bytes memory payload = abi.encode(msg.sender, interchainCall.calls);
90:
91: if (interchainCall.gas > 0) { // <= FOUND
92: gasService.payNativeGasForContractCall{ value: interchainCall.gas }(
93: address(this),
94: interchainCall.destinationChain,
95: interchainCall.destinationContract,
96: payload,
97: msg.sender
98: );
99: }
100:
101: gateway.callContract(interchainCall.destinationChain, interchainCall.destinationContract, payload);
102: }
156: function _onTargetExecutionFailed(
157: InterchainCalls.Call memory,
158: bytes memory result
159: ) internal virtual {
160:
161: if (result.length > 0) { // <= FOUND
162:
163: assembly {
164: revert(add(32, result), mload(result))
165: }
166: } else {
167:
168: revert ProposalExecuteFailed();
169: }
170: }
52: function upgrade(
53: address newImplementation,
54: bytes32 newImplementationCodeHash,
55: bytes calldata params
56: ) external override onlyOwner {
57: if (IUpgradable(newImplementation).contractId() != IUpgradable(this).contractId()) revert InvalidImplementation();
58: if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();
59:
60: if (params.length > 0) { // <= FOUND
61: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params));
62:
63: if (!success) revert SetupFailed();
64: }
65:
66: emit Upgraded(newImplementation);
67:
68: assembly {
69: sstore(_IMPLEMENTATION_SLOT, newImplementation)
70: }
71: }
502: function transmitSendToken(
503: bytes32 tokenId,
504: address sourceAddress,
505: string calldata destinationChain,
506: bytes memory destinationAddress,
507: uint256 amount,
508: bytes calldata metadata
509: ) external payable onlyTokenManager(tokenId) notPaused {
510: bytes memory payload;
511: if (metadata.length < 4) {
512: payload = abi.encode(SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount);
513: _callContract(destinationChain, payload, msg.value, sourceAddress);
514: emit TokenSent(tokenId, destinationChain, destinationAddress, amount);
515: return;
516: }
517: uint32 version;
518: (version, metadata) = _decodeMetadata(metadata);
519: if (version > 0) revert InvalidMetadataVersion(version); // <= FOUND
520: payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata);
521: _callContract(destinationChain, payload, msg.value, sourceAddress);
522: emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata);
523: }
678: function _processDeployStandardizedTokenAndManagerPayload(bytes calldata payload) internal {
679: (
680: ,
681: bytes32 tokenId,
682: string memory name,
683: string memory symbol,
684: uint8 decimals,
685: bytes memory distributorBytes,
686: bytes memory operatorBytes
687: ) = abi.decode(payload, (uint256, bytes32, string, string, uint8, bytes, bytes));
688: address tokenAddress = getStandardizedTokenAddress(tokenId);
689: address tokenManagerAddress = getTokenManagerAddress(tokenId);
690: address distributor = distributorBytes.length > 0 ? distributorBytes.toAddress() : tokenManagerAddress; // <= FOUND
691: _deployStandardizedToken(tokenId, distributor, name, symbol, decimals, 0, distributor);
692: TokenManagerType tokenManagerType = distributor == tokenManagerAddress ? TokenManagerType.MINT_BURN : TokenManagerType.LOCK_UNLOCK;
693: _deployTokenManager(
694: tokenId,
695: tokenManagerType,
696: abi.encode(operatorBytes.length == 0 ? address(this).toBytes() : operatorBytes, tokenAddress)
697: );
698: }
707: function _callContract(
708: string calldata destinationChain,
709: bytes memory payload,
710: uint256 gasValue,
711: address refundTo
712: ) internal {
713: string memory destinationAddress = remoteAddressValidator.getRemoteAddress(destinationChain);
714: if (gasValue > 0) { // <= FOUND
715: gasService.payNativeGasForContractCall{ value: gasValue }(
716: address(this),
717: destinationChain,
718: destinationAddress,
719: payload,
720: refundTo
721: );
722: }
723: gateway.callContract(destinationChain, destinationAddress, payload);
724: }
49: function setup(bytes calldata params) external override onlyProxy {
50: {
51: address distributor_;
52: address tokenManager_;
53: string memory tokenName;
54: (tokenManager_, distributor_, tokenName, symbol, decimals) = abi.decode(params, (address, address, string, string, uint8));
55: _setDistributor(distributor_);
56: tokenManager = tokenManager_;
57: _setDomainTypeSignatureHash(tokenName);
58: name = tokenName;
59: }
60: {
61: uint256 mintAmount;
62: address mintTo;
63: (, , , , , mintAmount, mintTo) = abi.decode(params, (address, address, string, string, uint8, uint256, address));
64: if (mintAmount > 0) { // <= FOUND
65: _mint(mintTo, mintAmount);
66: }
67: }
68: }
14
Using unchecked increments in Solidity can save on gas fees by bypassing built-in overflow checks, thus optimizing gas usage, but requires careful assessment of potential risks and edge cases to avoid unintended consequences.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L122-L124
119: function getSignerVotesCount(bytes32 topic) external view override returns (uint256) {
120: uint256 length = signers.accounts.length;
121: uint256 voteCount;
122: for (uint256 i; i < length; ++i) { // <= FOUND
123: if (votingPerTopic[signerEpoch][topic].hasVoted[signers.accounts[i]]) {
124: voteCount++; // <= FOUND
125: }
126: }
127:
128: return voteCount;
129: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L153-L168
149: function _rotateSigners(address[] memory newAccounts, uint256 newThreshold) internal {
150: uint256 length = signers.accounts.length;
151:
152:
153: for (uint256 i; i < length; ++i) { // <= FOUND
154: signers.isSigner[signers.accounts[i]] = false;
155: }
156:
157: length = newAccounts.length;
158:
159: if (newThreshold > length) revert InvalidSigners();
160:
161: if (newThreshold == 0) revert InvalidSignerThreshold();
162:
163: ++signerEpoch; // <= FOUND
164:
165: signers.accounts = newAccounts;
166: signers.threshold = newThreshold;
167:
168: for (uint256 i; i < length; ++i) { // <= FOUND
169: address account = newAccounts[i];
170:
171:
172: if (signers.isSigner[account]) revert DuplicateSigner(account);
173: if (account == address(0)) revert InvalidSigners();
174:
175: signers.isSigner[account] = true;
176: }
177:
178: emit SignersRotated(newAccounts, newThreshold);
179: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L269-L269
265: function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external override onlyMintLimiter {
266: uint256 length = symbols.length;
267: if (length != limits.length) revert InvalidSetMintLimitsParams();
268:
269: for (uint256 i; i < length; ++i) { // <= FOUND
270: string memory symbol = symbols[i];
271: uint256 limit = limits[i];
272:
273: if (tokenAddresses(symbol) == address(0)) revert TokenDoesNotExist(symbol);
274:
275: _setTokenMintLimit(symbol, limit);
276: }
277: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L343-L343
322: function execute(bytes calldata input) external override {
323: (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));
324:
325: bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data));
326:
327:
328: bool allowOperatorshipTransfer = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);
329:
330: uint256 chainId;
331: bytes32[] memory commandIds;
332: string[] memory commands;
333: bytes[] memory params;
334:
335: (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));
336:
337: if (chainId != block.chainid) revert InvalidChainId();
338:
339: uint256 commandsLength = commandIds.length;
340:
341: if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
342:
343: for (uint256 i; i < commandsLength; ++i) { // <= FOUND
344: bytes32 commandId = commandIds[i];
345:
346: if (isCommandExecuted(commandId)) continue;
347:
348: bytes4 commandSelector;
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));
350:
351: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
352: commandSelector = AxelarGateway.deployToken.selector;
353: } else if (commandHash == SELECTOR_MINT_TOKEN) {
354: commandSelector = AxelarGateway.mintToken.selector;
355: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
356: commandSelector = AxelarGateway.approveContractCall.selector;
357: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
358: commandSelector = AxelarGateway.approveContractCallWithMint.selector;
359: } else if (commandHash == SELECTOR_BURN_TOKEN) {
360: commandSelector = AxelarGateway.burnToken.selector;
361: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
362: if (!allowOperatorshipTransfer) continue;
363:
364: allowOperatorshipTransfer = false;
365: commandSelector = AxelarGateway.transferOperatorship.selector;
366: } else {
367: continue;
73: function _executeProposal(InterchainCalls.Call[] memory calls) internal {
74: for (uint256 i = 0; i < calls.length; i++) { // <= FOUND
75: InterchainCalls.Call memory call = calls[i];
76: (bool success, bytes memory result) = call.target.call{ value: call.value }(call.callData);
77:
78: if (!success) {
79: _onTargetExecutionFailed(call, result);
80: } else {
81: _onTargetExecuted(call, result);
82: }
83: }
84: }
534: function setFlowLimit(bytes32[] calldata tokenIds, uint256[] calldata flowLimits) external onlyOperator {
535: uint256 length = tokenIds.length;
536: if (length != flowLimits.length) revert LengthMismatch();
537: for (uint256 i; i < length; ++i) { // <= FOUND
538: ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenIds[i]));
539: tokenManager.setFlowLimit(flowLimits[i]);
540: }
541: }
40: function _setup(bytes calldata params) internal override {
41: (string[] memory trustedChainNames, string[] memory trustedAddresses) = abi.decode(params, (string[], string[]));
42: uint256 length = trustedChainNames.length;
43: if (length != trustedAddresses.length) revert LengthMismatch();
44: for (uint256 i; i < length; ++i) { // <= FOUND
45: addTrustedAddress(trustedChainNames[i], trustedAddresses[i]);
46: }
47: }
54: function _lowerCase(string memory s) internal pure returns (string memory) {
55: uint256 length = bytes(s).length;
56: for (uint256 i; i < length; i++) { // <= FOUND
57: uint8 b = uint8(bytes(s)[i]);
58: if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32));
59: }
60: return s;
61: }
106: function addGatewaySupportedChains(string[] calldata chainNames) external onlyOwner {
107: uint256 length = chainNames.length;
108: for (uint256 i; i < length; ++i) { // <= FOUND
109: string calldata chainName = chainNames[i];
110: supportedByGateway[chainName] = true;
111: emit GatewaySupportedChainAdded(chainName);
112: }
113: }
119: function removeGatewaySupportedChains(string[] calldata chainNames) external onlyOwner {
120: uint256 length = chainNames.length;
121: for (uint256 i; i < length; ++i) { // <= FOUND
122: string calldata chainName = chainNames[i];
123: supportedByGateway[chainName] = false;
124: emit GatewaySupportedChainRemoved(chainName);
125: }
126: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L24-L24
22: function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) {
23: results = new bytes[](data.length);
24: for (uint256 i = 0; i < data.length; ++i) { // <= FOUND
25: (bool success, bytes memory result) = address(this).delegatecall(data[i]);
26:
27: if (!success) {
28: revert(string(result));
29: }
30:
31: results[i] = result;
32: }
33: }
8
Using .delete is better than resetting a Solidity variable to its default value manually because it frees up storage space on the Ethereum blockchain, resulting in gas cost savings.
Findings are labeled with ' <= FOUND'
Click to show findings
48: function executeMultisigProposal(
49: address target,
50: bytes calldata callData,
51: uint256 nativeValue
52: ) external payable onlySigners {
53: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue));
54:
55: if (!multisigApprovals[proposalHash]) revert NotApproved();
56:
57: multisigApprovals[proposalHash] = false; // <= FOUND
58:
59: _call(target, callData, nativeValue);
60:
61: emit MultisigExecuted(proposalHash, target, callData, nativeValue);
62: }
72: function _processCommand(
73: uint256 commandId,
74: address target,
75: bytes memory callData,
76: uint256 nativeValue,
77: uint256 eta
78: ) internal override {
79: if (commandId > uint256(type(ServiceGovernanceCommand).max)) {
80: revert InvalidCommand();
81: }
82:
83: ServiceGovernanceCommand command = ServiceGovernanceCommand(commandId);
84: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue));
85:
86: if (command == ServiceGovernanceCommand.ScheduleTimeLockProposal) {
87: eta = _scheduleTimeLock(proposalHash, eta);
88:
89: emit ProposalScheduled(proposalHash, target, callData, nativeValue, eta);
90: return;
91: } else if (command == ServiceGovernanceCommand.CancelTimeLockProposal) {
92: _cancelTimeLock(proposalHash);
93:
94: emit ProposalCancelled(proposalHash, target, callData, nativeValue, eta);
95: return;
96: } else if (command == ServiceGovernanceCommand.ApproveMultisigProposal) {
97: multisigApprovals[proposalHash] = true;
98:
99: emit MultisigApproved(proposalHash, target, callData, nativeValue);
100: return;
101: } else if (command == ServiceGovernanceCommand.CancelMultisigApproval) {
102: multisigApprovals[proposalHash] = false; // <= FOUND
103:
104: emit MultisigCancelled(proposalHash, target, callData, nativeValue);
105: return;
106: }
107: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L149-L154
149: function _rotateSigners(address[] memory newAccounts, uint256 newThreshold) internal { // <= FOUND
150: uint256 length = signers.accounts.length;
151:
152:
153: for (uint256 i; i < length; ++i) {
154: signers.isSigner[signers.accounts[i]] = false; // <= FOUND
155: }
156:
157: length = newAccounts.length;
158:
159: if (newThreshold > length) revert InvalidSigners();
160:
161: if (newThreshold == 0) revert InvalidSignerThreshold();
162:
163: ++signerEpoch;
164:
165: signers.accounts = newAccounts;
166: signers.threshold = newThreshold;
167:
168: for (uint256 i; i < length; ++i) {
169: address account = newAccounts[i];
170:
171:
172: if (signers.isSigner[account]) revert DuplicateSigner(account);
173: if (account == address(0)) revert InvalidSigners();
174:
175: signers.isSigner[account] = true;
176: }
177:
178: emit SignersRotated(newAccounts, newThreshold);
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L322-L364
322: function execute(bytes calldata input) external override { // <= FOUND
323: (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));
324:
325: bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data));
326:
327:
328: bool allowOperatorshipTransfer = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);
329:
330: uint256 chainId;
331: bytes32[] memory commandIds;
332: string[] memory commands;
333: bytes[] memory params;
334:
335: (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));
336:
337: if (chainId != block.chainid) revert InvalidChainId();
338:
339: uint256 commandsLength = commandIds.length;
340:
341: if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
342:
343: for (uint256 i; i < commandsLength; ++i) {
344: bytes32 commandId = commandIds[i];
345:
346: if (isCommandExecuted(commandId)) continue;
347:
348: bytes4 commandSelector;
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));
350:
351: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
352: commandSelector = AxelarGateway.deployToken.selector;
353: } else if (commandHash == SELECTOR_MINT_TOKEN) {
354: commandSelector = AxelarGateway.mintToken.selector;
355: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
356: commandSelector = AxelarGateway.approveContractCall.selector;
357: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
358: commandSelector = AxelarGateway.approveContractCallWithMint.selector;
359: } else if (commandHash == SELECTOR_BURN_TOKEN) {
360: commandSelector = AxelarGateway.burnToken.selector;
361: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
362: if (!allowOperatorshipTransfer) continue;
363:
364: allowOperatorshipTransfer = false; // <= FOUND
365: commandSelector = AxelarGateway.transferOperatorship.selector;
366: } else {
367: continue;
368: }
369:
370:
371: _setCommandExecuted(commandId, true);
372:
373: (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId));
374:
375: if (success) emit Executed(commandId);
376: else _setCommandExecuted(commandId, false);
377: }
378: }
119: function removeGatewaySupportedChains(string[] calldata chainNames) external onlyOwner { // <= FOUND
120: uint256 length = chainNames.length;
121: for (uint256 i; i < length; ++i) {
122: string calldata chainName = chainNames[i];
123: supportedByGateway[chainName] = false; // <= FOUND
124: emit GatewaySupportedChainRemoved(chainName);
125: }
126: }
1
Make such found comparisons to the <=/>= equivalent when comparing against integer literals
Findings are labeled with ' <= FOUND'
Click to show findings
502: function transmitSendToken(
503: bytes32 tokenId,
504: address sourceAddress,
505: string calldata destinationChain,
506: bytes memory destinationAddress,
507: uint256 amount,
508: bytes calldata metadata
509: ) external payable onlyTokenManager(tokenId) notPaused {
510: bytes memory payload;
511: if (metadata.length < 4) { // <= FOUND
512: payload = abi.encode(SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount);
513: _callContract(destinationChain, payload, msg.value, sourceAddress);
514: emit TokenSent(tokenId, destinationChain, destinationAddress, amount);
515: return;
516: }
517: uint32 version;
518: (version, metadata) = _decodeMetadata(metadata);
519: if (version > 0) revert InvalidMetadataVersion(version);
520: payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata);
521: _callContract(destinationChain, payload, msg.value, sourceAddress);
522: emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata);
523: }
34
Cache such variables and perform operations on them, if operations include modifications to the state variable(s) then remember to equate the state variable to it's cached counterpart at the end
Findings are labeled with ' <= FOUND'
Click to show findings
43: function interchainTransfer( // <= FOUND
44: string calldata destinationChain,
45: bytes calldata recipient,
46: uint256 amount,
47: bytes calldata metadata
48: ) external payable {
49: address sender = msg.sender;
50: ITokenManager tokenManager = getTokenManager(); // <= FOUND
51:
52:
53:
54: if (tokenManagerRequiresApproval()) { // <= FOUND
55: uint256 allowance_ = allowance[sender][address(tokenManager)]; // <= FOUND
56: if (allowance_ != type(uint256).max) { // <= FOUND
57: if (allowance_ > type(uint256).max - amount) { // <= FOUND
58: allowance_ = type(uint256).max - amount; // <= FOUND
59: }
60:
61: _approve(sender, address(tokenManager), allowance_ + amount); // <= FOUND
62: }
63: }
64:
65:
66: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata); // <= FOUND
67: }
79: function interchainTransferFrom( // <= FOUND
80: address sender,
81: string calldata destinationChain,
82: bytes calldata recipient,
83: uint256 amount,
84: bytes calldata metadata
85: ) external payable {
86: uint256 _allowance = allowance[sender][msg.sender];
87:
88: if (_allowance != type(uint256).max) { // <= FOUND
89: _approve(sender, msg.sender, _allowance - amount);
90: }
91:
92: ITokenManager tokenManager = getTokenManager(); // <= FOUND
93: if (tokenManagerRequiresApproval()) { // <= FOUND
94: uint256 allowance_ = allowance[sender][address(tokenManager)]; // <= FOUND
95: if (allowance_ != type(uint256).max) { // <= FOUND
96: if (allowance_ > type(uint256).max - amount) { // <= FOUND
97: allowance_ = type(uint256).max - amount; // <= FOUND
98: }
99:
100: _approve(sender, address(tokenManager), allowance_ + amount); // <= FOUND
101: }
102: }
103:
104: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata); // <= FOUND
105: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L384-L417
384: function deployToken(bytes calldata params, bytes32) external onlySelf { // <= FOUND
385: (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode( // <= FOUND
386: params,
387: (string, string, uint8, uint256, address, uint256)
388: );
389:
390:
391: if (tokenAddresses(symbol) != address(0)) revert TokenAlreadyExists(symbol); // <= FOUND
392:
393: if (tokenAddress == address(0)) {
394:
395: bytes32 salt = keccak256(abi.encodePacked(symbol)); // <= FOUND
396:
397: (bool success, bytes memory data) = TOKEN_DEPLOYER_IMPLEMENTATION.delegatecall(
398: abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt) // <= FOUND
399: );
400:
401: if (!success) revert TokenDeployFailed(symbol); // <= FOUND
402:
403: tokenAddress = abi.decode(data, (address));
404:
405: _setTokenType(symbol, TokenType.InternalBurnableFrom); // <= FOUND
406: } else {
407:
408: if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);
409:
410:
411: _setTokenType(symbol, TokenType.External); // <= FOUND
412: }
413:
414: _setTokenAddress(symbol, tokenAddress); // <= FOUND
415: _setTokenMintLimit(symbol, mintLimit); // <= FOUND
416:
417: emit TokenDeployed(symbol, tokenAddress); // <= FOUND
418: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L96-L103
96: function sendToken( // <= FOUND
97: string calldata destinationChain,
98: string calldata destinationAddress,
99: string calldata symbol, // <= FOUND
100: uint256 amount
101: ) external {
102: _burnTokenFrom(msg.sender, symbol, amount); // <= FOUND
103: emit TokenSent(msg.sender, destinationChain, destinationAddress, symbol, amount); // <= FOUND
104: }
3
Cache such mappings and perform operations on them, if operations include modifications to the mapping(s) then remember to equate the mapping to it's cached counterpart at the end
Findings are labeled with ' <= FOUND'
Click to show findings
48: function executeMultisigProposal( // <= FOUND
49: address target,
50: bytes calldata callData,
51: uint256 nativeValue
52: ) external payable onlySigners {
53: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue));
54:
55: if (!multisigApprovals[proposalHash]) revert NotApproved(); // <= FOUND
56:
57: multisigApprovals[proposalHash] = false; // <= FOUND
58:
59: _call(target, callData, nativeValue);
60:
61: emit MultisigExecuted(proposalHash, target, callData, nativeValue);
62: }
18
Using assembly for address comparisons in Solidity can save gas because it allows for more direct access to the Ethereum Virtual Machine (EVM), reducing the overhead of higher-level operations. Solidity's high-level abstraction simplifies coding but can introduce additional gas costs. Using assembly for simple operations like address comparisons can be more gas-efficient.
Findings are labeled with ' <= FOUND'
Click to show findings
87: function _execute(
88: string calldata sourceChain,
89: string calldata sourceAddress,
90: bytes calldata payload
91: ) internal override {
92: if (keccak256(bytes(sourceChain)) != governanceChainHash || keccak256(bytes(sourceAddress)) != governanceAddressHash)
93: revert NotGovernance();
94:
95: (uint256 command, address target, bytes memory callData, uint256 nativeValue, uint256 eta) = abi.decode(
96: payload,
97: (uint256, address, bytes, uint256, uint256)
98: );
99:
100: if (target == address(0)) revert InvalidTarget(); // <= FOUND
101:
102: _processCommand(command, target, callData, nativeValue, eta);
103: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L149-L173
149: function _rotateSigners(address[] memory newAccounts, uint256 newThreshold) internal {
150: uint256 length = signers.accounts.length;
151:
152:
153: for (uint256 i; i < length; ++i) {
154: signers.isSigner[signers.accounts[i]] = false;
155: }
156:
157: length = newAccounts.length;
158:
159: if (newThreshold > length) revert InvalidSigners();
160:
161: if (newThreshold == 0) revert InvalidSignerThreshold();
162:
163: ++signerEpoch;
164:
165: signers.accounts = newAccounts;
166: signers.threshold = newThreshold;
167:
168: for (uint256 i; i < length; ++i) {
169: address account = newAccounts[i];
170:
171:
172: if (signers.isSigner[account]) revert DuplicateSigner(account);
173: if (account == address(0)) revert InvalidSigners(); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L253-L254
253: function transferGovernance(address newGovernance) external override onlyGovernance {
254: if (newGovernance == address(0)) revert InvalidGovernance(); // <= FOUND
255:
256: _transferGovernance(newGovernance);
257: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L259-L260
259: function transferMintLimiter(address newMintLimiter) external override onlyMintLimiter {
260: if (newMintLimiter == address(0)) revert InvalidMintLimiter(); // <= FOUND
261:
262: _transferMintLimiter(newMintLimiter);
263: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L265-L273
265: function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external override onlyMintLimiter {
266: uint256 length = symbols.length;
267: if (length != limits.length) revert InvalidSetMintLimitsParams();
268:
269: for (uint256 i; i < length; ++i) {
270: string memory symbol = symbols[i];
271: uint256 limit = limits[i];
272:
273: if (tokenAddresses(symbol) == address(0)) revert TokenDoesNotExist(symbol); // <= FOUND
274:
275: _setTokenMintLimit(symbol, limit);
276: }
277: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L306-L313
306: function setup(bytes calldata params) external override {
307:
308: if (implementation() == address(0)) revert NotProxy(); // <= FOUND
309:
310: (address governance_, address mintLimiter_, bytes memory newOperatorsData) = abi.decode(params, (address, address, bytes));
311:
312: if (governance_ != address(0)) _transferGovernance(governance_); // <= FOUND
313: if (mintLimiter_ != address(0)) _transferMintLimiter(mintLimiter_); // <= FOUND
314:
315: if (newOperatorsData.length != 0) {
316: IAxelarAuth(AUTH_MODULE).transferOperatorship(newOperatorsData);
317:
318: emit OperatorshipTransferred(newOperatorsData);
319: }
320: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L384-L393
384: function deployToken(bytes calldata params, bytes32) external onlySelf {
385: (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode(
386: params,
387: (string, string, uint8, uint256, address, uint256)
388: );
389:
390:
391: if (tokenAddresses(symbol) != address(0)) revert TokenAlreadyExists(symbol); // <= FOUND
392:
393: if (tokenAddress == address(0)) { // <= FOUND
394:
395: bytes32 salt = keccak256(abi.encodePacked(symbol));
396:
397: (bool success, bytes memory data) = TOKEN_DEPLOYER_IMPLEMENTATION.delegatecall(
398: abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt)
399: );
400:
401: if (!success) revert TokenDeployFailed(symbol);
402:
403: tokenAddress = abi.decode(data, (address));
404:
405: _setTokenType(symbol, TokenType.InternalBurnableFrom);
406: } else {
407:
408: if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L426-L431
426: function burnToken(bytes calldata params, bytes32) external onlySelf {
427: (string memory symbol, bytes32 salt) = abi.decode(params, (string, bytes32));
428:
429: address tokenAddress = tokenAddresses(symbol);
430:
431: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol); // <= FOUND
432:
433: if (_getTokenType(symbol) == TokenType.External) {
434: address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode)));
435:
436: if (_hasCode(depositHandlerAddress)) return;
437:
438: DepositHandler depositHandler = new DepositHandler{ salt: salt }();
439:
440: (bool success, bytes memory returnData) = depositHandler.execute(
441: tokenAddress,
442: abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler)))
443: );
444:
445: if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol);
446:
447:
448: depositHandler.destroy(address(this));
449: } else {
450: IBurnableMintableCappedERC20(tokenAddress).burn(salt);
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L511-L518
511: function _mintToken(
512: string memory symbol,
513: address account,
514: uint256 amount
515: ) internal {
516: address tokenAddress = tokenAddresses(symbol);
517:
518: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol); // <= FOUND
519:
520: _setTokenMintAmount(symbol, tokenMintAmount(symbol) + amount);
521:
522: if (_getTokenType(symbol) == TokenType.External) {
523: IERC20(tokenAddress).safeTransfer(account, amount);
524: } else {
525: IBurnableMintableCappedERC20(tokenAddress).mint(account, amount);
526: }
527: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L529-L536
529: function _burnTokenFrom(
530: address sender,
531: string memory symbol,
532: uint256 amount
533: ) internal {
534: address tokenAddress = tokenAddresses(symbol);
535:
536: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol); // <= FOUND
537: if (amount == 0) revert InvalidAmount();
538:
539: TokenType tokenType = _getTokenType(symbol);
540:
541: if (tokenType == TokenType.External) {
542: IERC20(tokenAddress).safeTransferFrom(sender, address(this), amount);
543: } else if (tokenType == TokenType.InternalBurnableFrom) {
544: IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IBurnableMintableCappedERC20.burnFrom.selector, sender, amount));
545: } else {
546: IERC20(tokenAddress).safeTransferFrom(sender, IBurnableMintableCappedERC20(tokenAddress).depositAddress(bytes32(0)), amount);
547: IBurnableMintableCappedERC20(tokenAddress).burn(bytes32(0));
548: }
549: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L51-L60
51: function deploy(bytes32 salt, bytes memory bytecode) internal returns (address deployed) {
52: deployed = deployedAddress(address(this), salt);
53:
54: if (deployed.isContract()) revert AlreadyDeployed();
55: if (bytecode.length == 0) revert EmptyBytecode();
56:
57:
58: CreateDeployer deployer = new CreateDeployer{ salt: salt }();
59:
60: if (address(deployer) == address(0)) revert DeployFailed(); // <= FOUND
61:
62: deployer.deploy(bytecode);
63: }
37: function implementation() public view override(BaseProxy, IProxy) returns (address implementation_) {
38: implementation_ = _finalImplementation();
39: if (implementation_ == address(0)) { // <= FOUND
40: implementation_ = super.implementation();
41: }
42: }
48: function isFinal() public view returns (bool) {
49: return _finalImplementation() != address(0); // <= FOUND
50: }
57: function _finalImplementation() internal view virtual returns (address implementation_) {
58:
59:
60:
61: implementation_ = Create3.deployedAddress(address(this), FINAL_IMPLEMENTATION_SALT);
62:
63: if (implementation_.code.length == 0) implementation_ = address(0); // <= FOUND
64: }
559: function _sanitizeTokenManagerImplementation(address[] memory implementaions, TokenManagerType tokenManagerType)
560: internal
561: pure
562: returns (address implementation)
563: {
564: implementation = implementaions[uint256(tokenManagerType)];
565: if (implementation == address(0)) revert ZeroAddress(); // <= FOUND
566: if (ITokenManager(implementation).implementationType() != uint256(tokenManagerType)) revert InvalidTokenManagerImplementation();
567: }
7
In Solidity, using storage instead of memory for structs and arrays in function parameters can result in gas savings. When data is passed as a storage reference, the function operates directly on the original data stored in contract storage, without needing to create a copy. Conversely, when memory is used, a copy of the data is created, which incurs additional gas costs. However, it's essential to note that while using storage references can save gas, it also means that any changes made to the data inside the function will modify the original data stored in the contract, which may not always be the desired behavior. Therefore, developers should carefully consider the implications of using storage versus memory based on the specific requirements of their functions.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L142-L142
142: function rotateSigners(address[] memory newAccounts, uint256 newThreshold) external virtual onlySigners // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L149-L149
149: function _rotateSigners(address[] memory newAccounts, uint256 newThreshold) internal // <= FOUND
73: function _executeProposal(InterchainCalls.Call[] memory calls) internal // <= FOUND
559: function _sanitizeTokenManagerImplementation(address[] memory implementaions, TokenManagerType tokenManagerType) // <= FOUND
560: internal
561: pure
562: returns (address implementation)
563:
88: function _sendProposal(InterchainCalls.InterchainCall memory interchainCall) internal // <= FOUND
156: function _onTargetExecutionFailed(
157: InterchainCalls.Call memory, // <= FOUND
158: bytes memory result
159: ) internal virtual
178: function _onTargetExecuted(InterchainCalls.Call memory call, bytes memory result) internal virtual // <= FOUND
[GAS-20] Divisions which do not divide by -X cannot overflow or overflow so such operations can be unchecked to save gas
6
Make such found divisions are unchecked when ensured it is safe to do so
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L203-L203
202: function tokenMintAmount(string memory symbol) public view override returns (uint256) {
203: return getUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours)); // <= FOUND
204: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L636-L636
632: function _setTokenMintAmount(string memory symbol, uint256 amount) internal {
633: uint256 limit = tokenMintLimit(symbol);
634: if (limit > 0 && amount > limit) revert ExceedMintLimit(symbol);
635:
636: _setUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours), amount); // <= FOUND
637: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L64-L64
63: function getFlowOutAmount() external view returns (uint256 flowOutAmount) {
64: uint256 epoch = block.timestamp / EPOCH_TIME; // <= FOUND
65: uint256 slot = _getFlowOutSlot(epoch);
66: assembly {
67: flowOutAmount := sload(slot)
68: }
69: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L76-L76
75: function getFlowInAmount() external view returns (uint256 flowInAmount) {
76: uint256 epoch = block.timestamp / EPOCH_TIME; // <= FOUND
77: uint256 slot = _getFlowInSlot(epoch);
78: assembly {
79: flowInAmount := sload(slot)
80: }
81: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L114-L114
111: function _addFlowOut(uint256 flowOutAmount) internal {
112: uint256 flowLimit = getFlowLimit();
113: if (flowLimit == 0) return;
114: uint256 epoch = block.timestamp / EPOCH_TIME; // <= FOUND
115: uint256 slotToAdd = _getFlowOutSlot(epoch);
116: uint256 slotToCompare = _getFlowInSlot(epoch);
117: _addFlow(flowLimit, slotToAdd, slotToCompare, flowOutAmount);
118: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L127-L127
124: function _addFlowIn(uint256 flowInAmount) internal {
125: uint256 flowLimit = getFlowLimit();
126: if (flowLimit == 0) return;
127: uint256 epoch = block.timestamp / EPOCH_TIME; // <= FOUND
128: uint256 slotToAdd = _getFlowInSlot(epoch);
129: uint256 slotToCompare = _getFlowOutSlot(epoch);
130: _addFlow(flowLimit, slotToAdd, slotToCompare, flowInAmount);
131: }
[GAS-21] State variables which are not modified within functions should be set as constants or immutable for values set at deployment
3
Set state variables listed below as constant or immutable for values set at deployment. Ensure it is safe to do so
Findings are labeled with ' <= FOUND'
Click to show findings
21: string public governanceChain;
22: string public governanceAddress;
14: ExpressCallHandler,
42
Using assembly to calculate hashes can save 80 gas per instance
Findings are labeled with ' <= FOUND'
Click to show findings
68: function executeProposal(
69: address target,
70: bytes calldata callData,
71: uint256 nativeValue
72: ) external payable {
73: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
74:
75: _finalizeTimeLock(proposalHash);
76: _call(target, callData, nativeValue);
77:
78: emit ProposalExecuted(proposalHash, target, callData, nativeValue, block.timestamp);
79: }
87: function _execute(
88: string calldata sourceChain,
89: string calldata sourceAddress,
90: bytes calldata payload
91: ) internal override {
92: if (keccak256(bytes(sourceChain)) != governanceChainHash || keccak256(bytes(sourceAddress)) != governanceAddressHash) // <= FOUND
93: revert NotGovernance();
94:
95: (uint256 command, address target, bytes memory callData, uint256 nativeValue, uint256 eta) = abi.decode(
96: payload,
97: (uint256, address, bytes, uint256, uint256)
98: );
99:
100: if (target == address(0)) revert InvalidTarget();
101:
102: _processCommand(command, target, callData, nativeValue, eta);
103: }
143: function _getProposalHash(
144: address target,
145: bytes memory callData,
146: uint256 nativeValue
147: ) internal pure returns (bytes32) {
148: return keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
149: }
48: function executeMultisigProposal(
49: address target,
50: bytes calldata callData,
51: uint256 nativeValue
52: ) external payable onlySigners {
53: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
54:
55: if (!multisigApprovals[proposalHash]) revert NotApproved();
56:
57: multisigApprovals[proposalHash] = false;
58:
59: _call(target, callData, nativeValue);
60:
61: emit MultisigExecuted(proposalHash, target, callData, nativeValue);
62: }
72: function _processCommand(
73: uint256 commandId,
74: address target,
75: bytes memory callData,
76: uint256 nativeValue,
77: uint256 eta
78: ) internal override {
79: if (commandId > uint256(type(ServiceGovernanceCommand).max)) {
80: revert InvalidCommand();
81: }
82:
83: ServiceGovernanceCommand command = ServiceGovernanceCommand(commandId);
84: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
85:
86: if (command == ServiceGovernanceCommand.ScheduleTimeLockProposal) {
87: eta = _scheduleTimeLock(proposalHash, eta);
88:
89: emit ProposalScheduled(proposalHash, target, callData, nativeValue, eta);
90: return;
91: } else if (command == ServiceGovernanceCommand.CancelTimeLockProposal) {
92: _cancelTimeLock(proposalHash);
93:
94: emit ProposalCancelled(proposalHash, target, callData, nativeValue, eta);
95: return;
96: } else if (command == ServiceGovernanceCommand.ApproveMultisigProposal) {
97: multisigApprovals[proposalHash] = true;
98:
99: emit MultisigApproved(proposalHash, target, callData, nativeValue);
100: return;
101: } else if (command == ServiceGovernanceCommand.CancelMultisigApproval) {
102: multisigApprovals[proposalHash] = false;
103:
104: emit MultisigCancelled(proposalHash, target, callData, nativeValue);
105: return;
106: }
107: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L111-L111
106: function callContract(
107: string calldata destinationChain,
108: string calldata destinationContractAddress,
109: bytes calldata payload
110: ) external {
111: emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload); // <= FOUND
112: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L122-L122
114: function callContractWithToken(
115: string calldata destinationChain,
116: string calldata destinationContractAddress,
117: bytes calldata payload,
118: string calldata symbol,
119: uint256 amount
120: ) external {
121: _burnTokenFrom(msg.sender, symbol, amount);
122: emit ContractCallWithToken(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload, symbol, amount); // <= FOUND
123: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L246-L246
245: function contractId() public pure returns (bytes32) {
246: return keccak256('axelar-gateway'); // <= FOUND
247: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L325-L349
322: function execute(bytes calldata input) external override {
323: (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));
324:
325: bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data)); // <= FOUND
326:
327:
328: bool allowOperatorshipTransfer = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);
329:
330: uint256 chainId;
331: bytes32[] memory commandIds;
332: string[] memory commands;
333: bytes[] memory params;
334:
335: (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));
336:
337: if (chainId != block.chainid) revert InvalidChainId();
338:
339: uint256 commandsLength = commandIds.length;
340:
341: if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
342:
343: for (uint256 i; i < commandsLength; ++i) {
344: bytes32 commandId = commandIds[i];
345:
346: if (isCommandExecuted(commandId)) continue;
347:
348: bytes4 commandSelector;
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i])); // <= FOUND
350:
351: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
352: commandSelector = AxelarGateway.deployToken.selector;
353: } else if (commandHash == SELECTOR_MINT_TOKEN) {
354: commandSelector = AxelarGateway.mintToken.selector;
355: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
356: commandSelector = AxelarGateway.approveContractCall.selector;
357: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
358: commandSelector = AxelarGateway.approveContractCallWithMint.selector;
359: } else if (commandHash == SELECTOR_BURN_TOKEN) {
360: commandSelector = AxelarGateway.burnToken.selector;
361: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
362: if (!allowOperatorshipTransfer) continue;
363:
364: allowOperatorshipTransfer = false;
365: commandSelector = AxelarGateway.transferOperatorship.selector;
366: } else {
367: continue;
368: }
369:
370:
371: _setCommandExecuted(commandId, true);
372:
373: (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId));
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L395-L395
384: function deployToken(bytes calldata params, bytes32) external onlySelf {
385: (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode(
386: params,
387: (string, string, uint8, uint256, address, uint256)
388: );
389:
390:
391: if (tokenAddresses(symbol) != address(0)) revert TokenAlreadyExists(symbol);
392:
393: if (tokenAddress == address(0)) {
394:
395: bytes32 salt = keccak256(abi.encodePacked(symbol)); // <= FOUND
396:
397: (bool success, bytes memory data) = TOKEN_DEPLOYER_IMPLEMENTATION.delegatecall(
398: abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt)
399: );
400:
401: if (!success) revert TokenDeployFailed(symbol);
402:
403: tokenAddress = abi.decode(data, (address));
404:
405: _setTokenType(symbol, TokenType.InternalBurnableFrom);
406: } else {
407:
408: if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);
409:
410:
411: _setTokenType(symbol, TokenType.External);
412: }
413:
414: _setTokenAddress(symbol, tokenAddress);
415: _setTokenMintLimit(symbol, mintLimit);
416:
417: emit TokenDeployed(symbol, tokenAddress);
418: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L434-L434
426: function burnToken(bytes calldata params, bytes32) external onlySelf {
427: (string memory symbol, bytes32 salt) = abi.decode(params, (string, bytes32));
428:
429: address tokenAddress = tokenAddresses(symbol);
430:
431: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
432:
433: if (_getTokenType(symbol) == TokenType.External) {
434: address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode))); // <= FOUND
435:
436: if (_hasCode(depositHandlerAddress)) return;
437:
438: DepositHandler depositHandler = new DepositHandler{ salt: salt }();
439:
440: (bool success, bytes memory returnData) = depositHandler.execute(
441: tokenAddress,
442: abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler)))
443: );
444:
445: if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol);
446:
447:
448: depositHandler.destroy(address(this));
449: } else {
450: IBurnableMintableCappedERC20(tokenAddress).burn(salt);
451: }
452: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L556-L556
555: function _getTokenMintLimitKey(string memory symbol) internal pure returns (bytes32) {
556: return keccak256(abi.encodePacked(PREFIX_TOKEN_MINT_LIMIT, symbol)); // <= FOUND
557: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L561-L561
559: function _getTokenMintAmountKey(string memory symbol, uint256 day) internal pure returns (bytes32) {
560:
561: return keccak256(abi.encode(PREFIX_TOKEN_MINT_AMOUNT, symbol, day)); // <= FOUND
562: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L565-L565
564: function _getTokenTypeKey(string memory symbol) internal pure returns (bytes32) {
565: return keccak256(abi.encodePacked(PREFIX_TOKEN_TYPE, symbol)); // <= FOUND
566: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L569-L569
568: function _getTokenAddressKey(string memory symbol) internal pure returns (bytes32) {
569: return keccak256(abi.encodePacked(PREFIX_TOKEN_ADDRESS, symbol)); // <= FOUND
570: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L573-L573
572: function _getIsCommandExecutedKey(bytes32 commandId) internal pure returns (bytes32) {
573: return keccak256(abi.encodePacked(PREFIX_COMMAND_EXECUTED, commandId)); // <= FOUND
574: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L583-L583
576: function _getIsContractCallApprovedKey(
577: bytes32 commandId,
578: string memory sourceChain,
579: string memory sourceAddress,
580: address contractAddress,
581: bytes32 payloadHash
582: ) internal pure returns (bytes32) {
583: return keccak256(abi.encode(PREFIX_CONTRACT_CALL_APPROVED, commandId, sourceChain, sourceAddress, contractAddress, payloadHash)); // <= FOUND
584: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L596-L596
586: function _getIsContractCallApprovedWithMintKey(
587: bytes32 commandId,
588: string memory sourceChain,
589: string memory sourceAddress,
590: address contractAddress,
591: bytes32 payloadHash,
592: string memory symbol,
593: uint256 amount
594: ) internal pure returns (bytes32) {
595: return
596: keccak256( // <= FOUND
597: abi.encode(
598: PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT,
599: commandId,
600: sourceChain,
601: sourceAddress,
602: contractAddress,
603: payloadHash,
604: symbol,
605: amount
606: )
607: );
608: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L615-L615
614: function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) {
615: return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash))))); // <= FOUND
616: }
41: function _execute(
42: string calldata sourceChain,
43: string calldata sourceAddress,
44: bytes calldata payload
45: ) internal override {
46: _beforeProposalExecuted(sourceChain, sourceAddress, payload);
47:
48:
49: if (!whitelistedSenders[sourceChain][StringToAddress.toAddress(sourceAddress)]) {
50: revert NotWhitelistedSourceAddress();
51: }
52:
53:
54: (address interchainProposalCaller, InterchainCalls.Call[] memory calls) = abi.decode(payload, (address, InterchainCalls.Call[]));
55:
56:
57: if (!whitelistedCallers[sourceChain][interchainProposalCaller]) {
58: revert NotWhitelistedCaller();
59: }
60:
61:
62: _executeProposal(calls);
63:
64: _onProposalExecuted(sourceChain, sourceAddress, interchainProposalCaller, payload);
65:
66: emit ProposalExecuted(keccak256(abi.encode(sourceChain, sourceAddress, interchainProposalCaller, payload))); // <= FOUND
67: }
24: function deploy(bytes memory bytecode, bytes32 salt) external returns (address deployedAddress_) {
25: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt))); // <= FOUND
26: }
42: function deployAndInit(
43: bytes memory bytecode,
44: bytes32 salt,
45: bytes calldata init
46: ) external returns (address deployedAddress_) {
47: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt))); // <= FOUND
48:
49:
50: (bool success, ) = deployedAddress_.call(init);
51: if (!success) revert FailedInit();
52: }
58: function deployedAddress(
59: bytes calldata bytecode,
60: address sender,
61: bytes32 salt
62: ) external view returns (address deployedAddress_) {
63: bytes32 newSalt = keccak256(abi.encode(sender, salt)); // <= FOUND
64: deployedAddress_ = address(
65: uint160(
66: uint256(
67: keccak256( // <= FOUND
68: abi.encodePacked(
69: hex'ff',
70: address(this),
71: newSalt,
72: keccak256(bytecode) // <= FOUND
73: )
74: )
75: )
76: )
77: );
78: }
29: function deploy(bytes calldata bytecode, bytes32 salt) external returns (address deployedAddress_) {
30: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt)); // <= FOUND
31: deployedAddress_ = Create3.deploy(deploySalt, bytecode);
32:
33: emit Deployed(keccak256(bytecode), salt, deployedAddress_); // <= FOUND
34: }
49: function deployAndInit(
50: bytes memory bytecode,
51: bytes32 salt,
52: bytes calldata init
53: ) external returns (address deployedAddress_) {
54: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt)); // <= FOUND
55: deployedAddress_ = Create3.deploy(deploySalt, bytecode);
56:
57: (bool success, ) = deployedAddress_.call(init);
58: if (!success) revert FailedInit();
59:
60: emit Deployed(keccak256(bytecode), salt, deployedAddress_); // <= FOUND
61: }
67: function deployedAddress(address sender, bytes32 salt) external view returns (address) {
68: bytes32 deploySalt = keccak256(abi.encode(sender, salt)); // <= FOUND
69: return Create3.deployedAddress(address(this), deploySalt);
70: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L72-L74
71: function deployedAddress(address sender, bytes32 salt) internal pure returns (address deployed) {
72: address deployer = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', sender, salt, DEPLOYER_BYTECODE_HASH))))); // <= FOUND
73:
74: deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01'))))); // <= FOUND
75: }
202: function getCanonicalTokenId(address tokenAddress) public view returns (bytes32 tokenId) {
203: tokenId = keccak256(abi.encode(PREFIX_STANDARDIZED_TOKEN_ID, chainNameHash, tokenAddress)); // <= FOUND
204: }
213: function getCustomTokenId(address sender, bytes32 salt) public pure returns (bytes32 tokenId) {
214: tokenId = keccak256(abi.encode(PREFIX_CUSTOM_TOKEN_ID, sender, salt)); // <= FOUND
215: }
827: function _getStandardizedTokenSalt(bytes32 tokenId) internal pure returns (bytes32 salt) {
828: return keccak256(abi.encode(PREFIX_STANDARDIZED_TOKEN_SALT, tokenId)); // <= FOUND
829: }
69: function validateSender(string calldata sourceChain, string calldata sourceAddress) external view returns (bool) {
70: string memory sourceAddressLC = _lowerCase(sourceAddress);
71: bytes32 sourceAddressHash = keccak256(bytes(sourceAddressLC)); // <= FOUND
72: if (sourceAddressHash == interchainTokenServiceAddressHash) {
73: return true;
74: }
75: return sourceAddressHash == remoteAddressHashes[sourceChain];
76: }
83: function addTrustedAddress(string memory chain, string memory addr) public onlyOwner {
84: if (bytes(chain).length == 0) revert ZeroStringLength();
85: if (bytes(addr).length == 0) revert ZeroStringLength();
86: remoteAddressHashes[chain] = keccak256(bytes(_lowerCase(addr))); // <= FOUND
87: remoteAddresses[chain] = addr;
88: emit TrustedAddressAdded(chain, addr);
89: }
26: function _getExpressReceiveTokenSlot(
27: bytes32 tokenId,
28: address destinationAddress,
29: uint256 amount,
30: bytes32 commandId
31: ) internal pure returns (uint256 slot) {
32: slot = uint256(keccak256(abi.encode(PREFIX_EXPRESS_RECEIVE_TOKEN, tokenId, destinationAddress, amount, commandId))); // <= FOUND
33: }
46: function _getExpressReceiveTokenWithDataSlot(
47: bytes32 tokenId,
48: string memory sourceChain,
49: bytes memory sourceAddress,
50: address destinationAddress,
51: uint256 amount,
52: bytes memory data,
53: bytes32 commandId
54: ) internal pure returns (uint256 slot) {
55: slot = uint256(
56: keccak256( // <= FOUND
57: abi.encode(
58: PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA,
59: tokenId,
60: sourceChain,
61: sourceAddress,
62: destinationAddress,
63: amount,
64: data,
65: commandId
66: )
67: )
68: );
69: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L47-L47
46: function _getFlowOutSlot(uint256 epoch) internal pure returns (uint256 slot) {
47: slot = uint256(keccak256(abi.encode(PREFIX_FLOW_OUT_AMOUNT, epoch))); // <= FOUND
48: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L56-L56
55: function _getFlowInSlot(uint256 epoch) internal pure returns (uint256 slot) {
56: slot = uint256(keccak256(abi.encode(PREFIX_FLOW_IN_AMOUNT, epoch))); // <= FOUND
57: }
1
Findings are labeled with ' <= FOUND'
Click to show findings
223: function getImplementation(uint256 tokenManagerType) external view returns (address tokenManagerAddress) { // <= FOUND
224:
225:
226: if (TokenManagerType(tokenManagerType) == TokenManagerType.LOCK_UNLOCK) {
227: return implementationLockUnlock;
228: } else if (TokenManagerType(tokenManagerType) == TokenManagerType.MINT_BURN) {
229: return implementationMintBurn;
230: } else if (TokenManagerType(tokenManagerType) == TokenManagerType.LIQUIDITY_POOL) {
231: return implementationLiquidityPool;
232: }
233: }
4
In the context of Solidity, external function calls without a specified gas limit present a significant risk. The callee contract has the potential to consume all the gas allocated to the transaction, causing an undesired revert and disrupt the function's execution. To mitigate this, it's recommended to explicitly set a gas limit when performing external calls using addr.call{gas: }. This limits the gas forwarded to the callee, preventing potential pitfalls and offering better control over transaction execution.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L322-L373
322: function execute(bytes calldata input) external override { // <= FOUND
323: (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));
324:
325: bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data));
326:
327:
328: bool allowOperatorshipTransfer = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);
329:
330: uint256 chainId;
331: bytes32[] memory commandIds;
332: string[] memory commands;
333: bytes[] memory params;
334:
335: (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));
336:
337: if (chainId != block.chainid) revert InvalidChainId();
338:
339: uint256 commandsLength = commandIds.length;
340:
341: if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
342:
343: for (uint256 i; i < commandsLength; ++i) {
344: bytes32 commandId = commandIds[i];
345:
346: if (isCommandExecuted(commandId)) continue;
347:
348: bytes4 commandSelector;
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));
350:
351: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
352: commandSelector = AxelarGateway.deployToken.selector;
353: } else if (commandHash == SELECTOR_MINT_TOKEN) {
354: commandSelector = AxelarGateway.mintToken.selector;
355: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
356: commandSelector = AxelarGateway.approveContractCall.selector;
357: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
358: commandSelector = AxelarGateway.approveContractCallWithMint.selector;
359: } else if (commandHash == SELECTOR_BURN_TOKEN) {
360: commandSelector = AxelarGateway.burnToken.selector;
361: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
362: if (!allowOperatorshipTransfer) continue;
363:
364: allowOperatorshipTransfer = false;
365: commandSelector = AxelarGateway.transferOperatorship.selector;
366: } else {
367: continue;
368: }
369:
370:
371: _setCommandExecuted(commandId, true);
372:
373: (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId)); // <= FOUND
374:
375: if (success) emit Executed(commandId);
376: else _setCommandExecuted(commandId, false);
377: }
378: }
42: function deployAndInit(
43: bytes memory bytecode,
44: bytes32 salt,
45: bytes calldata init
46: ) external returns (address deployedAddress_) {
47: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt)));
48:
49:
50: (bool success, ) = deployedAddress_.call(init); // <= FOUND
51: if (!success) revert FailedInit();
52: }
49: function deployAndInit(
50: bytes memory bytecode,
51: bytes32 salt,
52: bytes calldata init
53: ) external returns (address deployedAddress_) {
54: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt));
55: deployedAddress_ = Create3.deploy(deploySalt, bytecode);
56:
57: (bool success, ) = deployedAddress_.call(init); // <= FOUND
58: if (!success) revert FailedInit();
59:
60: emit Deployed(keccak256(bytecode), salt, deployedAddress_);
61: }
73
The Solidity compiler's Intermediate Representation (IR) based code generator, which can be activated using --via-ir on the command line or {"viaIR": true} in the options, serves a dual purpose. Firstly, it boosts the transparency and audibility of code generation, which enhances developers' comprehension and control over the contract's final bytecode. Secondly, it enables more sophisticated optimization passes that span multiple functions, thereby potentially leading to more efficient bytecode.
It's important to note that using the IR-based code generator may lengthen compile times due to the extra optimization steps. Therefore, it's advised to test your contract with and without this option enabled to measure the performance and gas cost implications. If the IR-based code generator significantly enhances your contract's performance or reduces gas costs, consider using the --via-ir flag during deployment. This way, you can leverage more advanced compiler optimizations without hindering your development workflow.
Findings are labeled with ' <= FOUND'
Click to show findings
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { Proxy } from '../../gmp-sdk/upgradable/Proxy.sol';
6:
7: /**
8: * @title RemoteAddressValidatorProxy
9: * @dev Proxy contract for the RemoteAddressValidator contract. Inherits from the Proxy contract.
10: */
11: contract RemoteAddressValidatorProxy is Proxy {
12: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator');
13:
14: /**
15: * @dev Constructs the RemoteAddressValidatorProxy contract.
16: * @param implementationAddress Address of the RemoteAddressValidator implementation
17: * @param owner Address of the owner of the proxy
18: * @param params The params to be passed to the _setup function of the implementation.
19: */
20: constructor(
21: address implementationAddress,
22: address owner,
23: bytes memory params
24: ) Proxy(implementationAddress, owner, params) {}
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title AddressBytesUtils
7: * @dev This library provides utility functions to convert between `address` and `bytes`.
8: */
9: library AddressBytesUtils {
10: error InvalidBytesLength(bytes bytesAddress);
11:
12: /**
13: * @dev Converts a bytes address to an address type.
14: * @param bytesAddress The bytes representation of an address
15: * @return addr The converted address
16: */
17: function toAddress(bytes memory bytesAddress) internal pure returns (address addr) {
18: if (bytesAddress.length != 20) revert InvalidBytesLength(bytesAddress);
19:
20: assembly {
21: addr := mload(add(bytesAddress, 20))
22: }
23: }
24:
25: /**
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: interface IOperatable {
6: error NotOperator();
7:
8: event OperatorChanged(address operator);
9:
10: /**
11: * @notice Get the address of the operator
12: * @return operator_ of the operator
13: */
14: function operator() external view returns (address operator_);
15:
16: /**
17: * @notice Change the operator of the contract
18: * @dev Can only be called by the current operator
19: * @param operator_ The address of the new operator
20: */
21: function setOperator(address operator_) external;
22: }
23:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4: import { IRemoteAddressValidator } from '../interfaces/IRemoteAddressValidator.sol';
5: import { AddressToString } from '../../gmp-sdk/util/AddressString.sol';
6: import { Upgradable } from '../../gmp-sdk/upgradable/Upgradable.sol';
7:
8: /**
9: * @title RemoteAddressValidator
10: * @dev Manages and validates remote addresses, keeps track of addresses supported by the Axelar gateway contract
11: */
12: contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable {
13: using AddressToString for address;
14:
15: mapping(string => bytes32) public remoteAddressHashes;
16: mapping(string => string) public remoteAddresses;
17: address public immutable interchainTokenServiceAddress;
18: bytes32 public immutable interchainTokenServiceAddressHash;
19: mapping(string => bool) public supportedByGateway;
20:
21: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator');
22:
23: /**
24: * @dev Constructs the RemoteAddressValidator contract, both array parameters must be equal in length
25: * @param _interchainTokenServiceAddress Address of the interchain token service
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: interface IImplementation {
6: error NotProxy();
7: }
8:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title ITokenManagerType
7: * @notice A simple interface that defines all the token manager types
8: */
9: interface ITokenManagerType {
10: enum TokenManagerType {
11: LOCK_UNLOCK,
12: MINT_BURN,
13: LIQUIDITY_POOL
14: }
15: }
16:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: interface IInterchainProposalExecutor {
6: // An event emitted when the proposal caller is whitelisted
7: event WhitelistedProposalCallerSet(string indexed sourceChain, address indexed sourceCaller, bool whitelisted);
8:
9: // An event emitted when the proposal sender is whitelisted
10: event WhitelistedProposalSenderSet(string indexed sourceChain, address indexed sourceSender, bool whitelisted);
11:
12: event ProposalExecuted(bytes32 indexed payloadHash);
13:
14: // An error emitted when the proposal execution failed
15: error ProposalExecuteFailed();
16:
17: // An error emitted when the proposal caller is not whitelisted
18: error NotWhitelistedCaller();
19:
20: // An error emitted when the proposal sender is not whitelisted
21: error NotWhitelistedSourceAddress();
22:
23: /**
24: * @notice set the whitelisted status of a proposal sender which is the `InterchainProposalSender` contract address on the source chain
25: * @param sourceChain The source chain
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IProxy } from '../interfaces/IProxy.sol';
6: import { IFinalProxy } from '../interfaces/IFinalProxy.sol';
7: import { Create3 } from '../deploy/Create3.sol';
8: import { BaseProxy } from './BaseProxy.sol';
9: import { Proxy } from './Proxy.sol';
10:
11: /**
12: * @title FinalProxy Contract
13: * @notice The FinalProxy contract is a proxy that can be upgraded to a final implementation
14: * that uses less gas than regular proxy calls. It inherits from the Proxy contract and implements
15: * the IFinalProxy interface.
16: */
17: contract FinalProxy is Proxy, IFinalProxy {
18: bytes32 internal constant FINAL_IMPLEMENTATION_SALT = keccak256('final-implementation');
19:
20: /**
21: * @dev Constructs a FinalProxy contract with a given implementation address, owner, and setup parameters.
22: * @param implementationAddress The address of the implementation contract
23: * @param owner The owner of the proxy contract
24: * @param setupParams Parameters to setup the implementation contract
25: */
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IProxy } from './IProxy.sol';
6:
7: // General interface for upgradable contracts
8: interface IFinalProxy is IProxy {
9: function isFinal() external view returns (bool);
10:
11: function finalUpgrade(bytes memory bytecode, bytes calldata setupParams) external returns (address);
12: }
13:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/interfaces/ICaller.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: interface ICaller {
6: error InsufficientBalance();
7: error ExecutionFailed();
8: }
9:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { ContractAddress } from '../util/ContractAddress.sol';
6:
7: error AlreadyDeployed();
8: error EmptyBytecode();
9: error DeployFailed();
10:
11: /**
12: * @title CreateDeployer Contract
13: * @notice This contract deploys new contracts using the `CREATE` opcode and is used as part of
14: * the `Create3` deployment method.
15: */
16: contract CreateDeployer {
17: /**
18: * @dev Deploys a new contract with the specified bytecode using the CREATE opcode.
19: * @param bytecode The bytecode of the contract to be deployed
20: */
21: function deploy(bytes memory bytecode) external {
22: address deployed;
23:
24: assembly {
25: deployed := create(0, add(bytecode, 32), mload(bytecode))
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { StandardizedToken } from './StandardizedToken.sol';
6:
7: contract StandardizedTokenMintBurn is StandardizedToken {
8: function tokenManagerRequiresApproval() public pure override returns (bool) {
9: return false;
10: }
11: }
12:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IOwnable } from './IOwnable.sol';
6:
7: // General interface for upgradable contracts
8: interface IUpgradable is IOwnable {
9: error InvalidCodeHash();
10: error InvalidImplementation();
11: error SetupFailed();
12: error NotProxy();
13:
14: event Upgraded(address indexed newImplementation);
15:
16: function implementation() external view returns (address);
17:
18: function upgrade(
19: address newImplementation,
20: bytes32 newImplementationCodeHash,
21: bytes calldata params
22: ) external;
23:
24: function setup(bytes calldata data) external;
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { ITokenManagerType } from './ITokenManagerType.sol';
6: import { IOperatable } from './IOperatable.sol';
7: import { IFlowLimit } from './IFlowLimit.sol';
8: import { IImplementation } from './IImplementation.sol';
9:
10: /**
11: * @title ITokenManager
12: * @notice This contract is responsible for handling tokens before initiating a cross chain token transfer, or after receiving one.
13: */
14: interface ITokenManager is ITokenManagerType, IOperatable, IFlowLimit, IImplementation {
15: error TokenLinkerZeroAddress();
16: error NotService();
17: error TakeTokenFailed();
18: error GiveTokenFailed();
19: error NotToken();
20:
21: /**
22: * @notice A function that should return the address of the token.
23: * Must be overridden in the inheriting contract.
24: * @return address address of the token.
25: */
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IUpgradable } from '../interfaces/IUpgradable.sol';
6: import { Ownable } from '../util/Ownable.sol';
7:
8: /**
9: * @title Upgradable Contract
10: * @notice This contract provides an interface for upgradable smart contracts and includes the functionality to perform upgrades.
11: */
12: abstract contract Upgradable is Ownable, IUpgradable {
13: // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
14: bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
15: address internal immutable implementationAddress;
16:
17: /**
18: * @notice Constructor sets the implementation address to the address of the contract itself
19: * @dev This is used in the onlyProxy modifier to prevent certain functions from being called directly
20: * on the implementation contract itself
21: */
22: constructor() {
23: implementationAddress = address(this);
24: }
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: contract ConstAddressDeployer {
6: error EmptyBytecode();
7: error FailedDeploy();
8: error FailedInit();
9:
10: event Deployed(bytes32 indexed bytecodeHash, bytes32 indexed salt, address indexed deployedAddress);
11:
12: /**
13: * @dev Deploys a contract using `CREATE2`. The address where the contract
14: * will be deployed can be known in advance via {deployedAddress}.
15: *
16: * The bytecode for a contract can be obtained from Solidity with
17: * `type(contractName).creationCode`.
18: *
19: * Requirements:
20: *
21: * - `bytecode` must not be empty.
22: * - `salt` must have not been used for `bytecode` already by the same `msg.sender`.
23: */
24: function deploy(bytes memory bytecode, bytes32 salt) external returns (address deployedAddress_) {
25: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt)));
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IMulticall } from '../interfaces/IMulticall.sol';
6:
7: /**
8: * @title Multicall
9: * @notice This contract is a multi-functional smart contract which allows for multiple
10: * contract calls in a single transaction.
11: */
12: contract Multicall is IMulticall {
13: error MulticallFailed(bytes err);
14:
15: /**
16: * @notice Performs multiple delegate calls and returns the results of all calls as an array
17: * @dev This function requires that the contract has sufficient balance for the delegate calls.
18: * If any of the calls fail, the function will revert with the failure message.
19: * @param data An array of encoded function calls
20: * @return results An bytes array with the return data of each function call
21: */
22: function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) {
23: results = new bytes[](data.length);
24: for (uint256 i = 0; i < data.length; ++i) {
25: (bool success, bytes memory result) = address(this).delegatecall(data[i]);
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IERC20 } from '../../gmp-sdk/interfaces/IERC20.sol';
6:
7: /**
8: * @dev Interface of the ERC20 standard as defined in the EIP.
9: */
10: interface IInterchainToken is IERC20 {
11: /**
12: * @notice Implementation of the interchainTransfer method
13: * @dev We chose to either pass `metadata` as raw data on a remote contract call, or, if no data is passed, just do a transfer.
14: * A different implementation could have `metadata` that tells this function which function to use or that it is used for anything else as well.
15: * @param destinationChain The destination chain identifier.
16: * @param recipient The bytes representation of the address of the recipient.
17: * @param amount The amount of token to be transfered.
18: * @param metadata Either empty, to just facilitate an interchain transfer, or the data can be passed for an interchain contract call with transfer as per semantics defined by the token service.
19: */
20: function interchainTransfer(
21: string calldata destinationChain,
22: bytes calldata recipient,
23: uint256 amount,
24: bytes calldata metadata
25: ) external payable;
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/interfaces/IMultisig.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IMultisigBase } from './IMultisigBase.sol';
6: import { ICaller } from './ICaller.sol';
7:
8: /**
9: * @title IMultisig Interface
10: * @notice This interface extends IMultisigBase by adding an execute function for multisignature transactions.
11: */
12: interface IMultisig is ICaller, IMultisigBase {
13: /**
14: * @notice Executes a function on an external target.
15: * @param target The address of the target to call
16: * @param callData The call data to be sent
17: * @param nativeValue The native token value to be sent (e.g., ETH)
18: */
19: function execute(
20: address target,
21: bytes calldata callData,
22: uint256 nativeValue
23: ) external payable;
24: }
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { Create3Deployer } from '../../gmp-sdk/deploy/Create3Deployer.sol';
6:
7: import { IStandardizedTokenDeployer } from '../interfaces/IStandardizedTokenDeployer.sol';
8:
9: import { StandardizedTokenProxy } from '../proxies/StandardizedTokenProxy.sol';
10:
11: /**
12: * @title StandardizedTokenDeployer
13: * @notice This contract is used to deploy new instances of the StandardizedTokenProxy contract.
14: */
15: contract StandardizedTokenDeployer is IStandardizedTokenDeployer {
16: Create3Deployer public immutable deployer;
17: address public immutable implementationMintBurnAddress;
18: address public immutable implementationLockUnlockAddress;
19:
20: /**
21: * @notice Constructor for the StandardizedTokenDeployer contract
22: * @param deployer_ Address of the Create3Deployer contract
23: * @param implementationLockUnlockAddress_ Address of the StandardizedTokenLockUnlock contract
24: * @param implementationMintBurnAddress_ Address of the StandardizedTokenMintBurn contract
25: */
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IMultisig } from '../interfaces/IMultisig.sol';
6: import { MultisigBase } from '../auth/MultisigBase.sol';
7: import { Caller } from '../util/Caller.sol';
8:
9: /**
10: * @title Multisig Contract
11: * @notice An extension of MultisigBase that can call functions on any contract.
12: */
13: contract Multisig is Caller, MultisigBase, IMultisig {
14: /**
15: * @notice Contract constructor
16: * @dev Sets the initial list of signers and corresponding threshold.
17: * @param accounts Address array of the signers
18: * @param threshold Signature threshold required to validate a transaction
19: */
20: constructor(address[] memory accounts, uint256 threshold) MultisigBase(accounts, threshold) {}
21:
22: /**
23: * @notice Executes an external contract call.
24: * @dev Calls a target address with specified calldata and optionally sends value.
25: * This function is protected by the onlySigners modifier.
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IAxelarGateway } from '../../gmp-sdk/interfaces/IAxelarGateway.sol';
6: import { IAxelarExecutable } from '../../gmp-sdk/interfaces/IAxelarExecutable.sol';
7:
8: import { IExpressCallHandler } from './IExpressCallHandler.sol';
9: import { ITokenManagerDeployer } from './ITokenManagerDeployer.sol';
10: import { ITokenManagerType } from './ITokenManagerType.sol';
11: import { IPausable } from './IPausable.sol';
12: import { IMulticall } from './IMulticall.sol';
13:
14: interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAxelarExecutable, IPausable, IMulticall {
15: // more generic error
16: error ZeroAddress();
17: error LengthMismatch();
18: error InvalidTokenManagerImplementation();
19: error NotRemoteService();
20: error TokenManagerDoesNotExist(bytes32 tokenId);
21: error NotTokenManager();
22: error ExecuteWithInterchainTokenFailed(address contractAddress);
23: error NotCanonicalTokenManager();
24: error GatewayToken();
25: error TokenManagerDeploymentFailed();
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { StandardizedToken } from './StandardizedToken.sol';
6:
7: contract StandardizedTokenLockUnlock is StandardizedToken {
8: function tokenManagerRequiresApproval() public pure override returns (bool) {
9: return true;
10: }
11: }
12:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IAxelarGateway } from '../gmp-sdk/interfaces/IAxelarGateway.sol';
6: import { IAxelarGasService } from '../gmp-sdk/interfaces/IAxelarGasService.sol';
7: import { IInterchainProposalSender } from './interfaces/IInterchainProposalSender.sol';
8: import { InterchainCalls } from './lib/InterchainCalls.sol';
9:
10: /**
11: * @title InterchainProposalSender
12: * @dev This contract is responsible for facilitating the execution of approved proposals across multiple chains.
13: * It achieves this by working in conjunction with the AxelarGateway and AxelarGasService contracts.
14: *
15: * The contract allows for the sending of a single proposal to multiple destination chains. This is achieved
16: * through the `sendProposals` function, which takes in arrays representing the destination chains,
17: * destination contracts, fees, target contracts, amounts of tokens to send, function signatures, and encoded
18: * function arguments.
19: *
20: * Each destination chain has a unique corresponding set of contracts to call, amounts of native tokens to send,
21: * function signatures to call, and encoded function arguments. This information is provided in a 2D array where
22: * the first dimension is the destination chain index, and the second dimension corresponds to the specific details
23: * for each chain.
24: *
25: * In addition, the contract also allows for the execution of a single proposal at a single destination chain
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: library InterchainCalls {
6: /**
7: * @dev An interchain call to be executed at the destination chain
8: * @param destinationChain destination chain
9: * @param destinationContract destination contract
10: * @param gas The amount of native token to transfer to the target contract as gas payment for the interchain call
11: * @param calls An array of calls to be executed at the destination chain
12: */
13: struct InterchainCall {
14: string destinationChain;
15: string destinationContract;
16: uint256 gas;
17: Call[] calls;
18: }
19:
20: /**
21: * @dev A call to be executed at the destination chain
22: * @param target The address of the contract to call
23: * @param value The amount of native token to transfer to the target contract
24: * @param callData The data to pass to the target contract
25: */
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IPausable } from '../interfaces/IPausable.sol';
6:
7: /**
8: * @title Pausable
9: * @notice This contract provides a mechanism to halt the execution of specific functions
10: * if a pause condition is activated.
11: */
12: contract Pausable is IPausable {
13: // uint256(keccak256('paused')) - 1
14: uint256 internal constant PAUSE_SLOT = 0xee35723ac350a69d2a92d3703f17439cbaadf2f093a21ba5bf5f1a53eb2a14d8;
15:
16: /**
17: * @notice A modifier that throws a Paused custom error if the contract is paused
18: * @dev This modifier should be used with functions that can be paused
19: */
20: modifier notPaused() {
21: if (isPaused()) revert Paused();
22: _;
23: }
24:
25: /**
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IFlowLimit } from '../interfaces/IFlowLimit.sol';
6:
7: /**
8: * @title FlowLimit
9: * @notice Implements flow limit logic for interchain token transfers.
10: * @dev This contract implements low-level assembly for optimization purposes.
11: */
12: contract FlowLimit is IFlowLimit {
13: // uint256(keccak256('flow-limit')) - 1
14: uint256 internal constant FLOW_LIMIT_SLOT = 0x201b7a0b7c19aaddc4ce9579b7df8d2db123805861bc7763627f13e04d8af42f;
15: uint256 internal constant PREFIX_FLOW_OUT_AMOUNT = uint256(keccak256('prefix-flow-out-amount'));
16: uint256 internal constant PREFIX_FLOW_IN_AMOUNT = uint256(keccak256('prefix-flow-in-amount'));
17:
18: uint256 internal constant EPOCH_TIME = 6 hours;
19:
20: /**
21: * @notice Returns the current flow limit
22: * @return flowLimit The current flow limit value
23: */
24: function getFlowLimit() public view returns (uint256 flowLimit) {
25: assembly {
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { ITokenManager } from '../interfaces/ITokenManager.sol';
6: import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol';
7: import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol';
8:
9: import { Operatable } from '../utils/Operatable.sol';
10: import { FlowLimit } from '../utils/FlowLimit.sol';
11: import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol';
12: import { Implementation } from '../utils/Implementation.sol';
13:
14: /**
15: * @title The main functionality of TokenManagers.
16: * @notice This contract is responsible for handling tokens before initiating a cross chain token transfer, or after receiving one.
17: */
18: abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implementation {
19: using AddressBytesUtils for bytes;
20:
21: IInterchainTokenService public immutable interchainTokenService;
22:
23: /**
24: * @notice Constructs the TokenManager contract.
25: * @param interchainTokenService_ The address of the interchain token service
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interfaces/IMulticall.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title IMulticall
7: * @notice This contract is a multi-functional smart contract which allows for multiple
8: * contract calls in a single transaction.
9: */
10: interface IMulticall {
11: /**
12: * @notice Performs multiple delegate calls and returns the results of all calls as an array
13: * @dev This function requires that the contract has sufficient balance for the delegate calls.
14: * If any of the calls fail, the function will revert with the failure message.
15: * @param data An array of encoded function calls
16: * @return results An bytes array with the return data of each function call
17: */
18: function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
19: }
20:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { Create3 } from './Create3.sol';
6:
7: /**
8: * @title Create3Deployer Contract
9: * @notice This contract is responsible for deploying and initializing new contracts using the CREATE3 technique
10: * which ensures that only the sender address and salt influence the deployed address, not the contract bytecode.
11: */
12: contract Create3Deployer {
13: error FailedInit();
14:
15: event Deployed(bytes32 indexed bytecodeHash, bytes32 indexed salt, address indexed deployedAddress);
16:
17: /**
18: * @dev Deploys a contract using `CREATE3`. The address where the contract
19: * will be deployed can be known in advance via {deployedAddress}.
20: *
21: * The bytecode for a contract can be obtained from Solidity with
22: * `type(contractName).creationCode`.
23: *
24: * Requirements:
25: *
1: // SPDX-License-Identifier: MIT
2: pragma solidity ^0.8.0;
3:
4: import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
5: import { StringToAddress } from '../gmp-sdk/util/AddressString.sol';
6: import { AxelarExecutable } from '../gmp-sdk/executable/AxelarExecutable.sol';
7: import { IInterchainProposalExecutor } from './interfaces/IInterchainProposalExecutor.sol';
8: import { InterchainCalls } from './lib/InterchainCalls.sol';
9:
10: /**
11: * @title InterchainProposalExecutor
12: * @dev This contract is intended to be the destination contract for `InterchainProposalSender` contract.
13: * The proposal will be finally executed from this contract on the destination chain.
14: *
15: * The contract maintains whitelists for proposal senders and proposal callers. Proposal senders
16: * are InterchainProposalSender contracts at the source chain and proposal callers are contracts
17: * that call the InterchainProposalSender at the source chain.
18: * For most governance system, the proposal caller should be the Timelock contract.
19: *
20: * This contract is abstract and some of its functions need to be implemented in a derived contract.
21: */
22: contract InterchainProposalExecutor is IInterchainProposalExecutor, AxelarExecutable, Ownable {
23: // Whitelisted proposal callers. The proposal caller is the contract that calls the `InterchainProposalSender` at the source chain.
24: mapping(string => mapping(address => bool)) public whitelistedCallers;
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IProxy } from '../interfaces/IProxy.sol';
6:
7: /**
8: * @title FixedProxy Contract
9: * @notice The FixedProxy is a type of Proxy contract with a fixed implementation that cannot be updated.
10: * It implements the IProxy interface. Any function calls to this contract will be forwarded to the implementation contract.
11: */
12: contract FixedProxy is IProxy {
13: /**
14: * @dev The immutable address of the implementation contract.
15: * This address is set in the constructor and cannot be updated after.
16: */
17: address public immutable implementation;
18:
19: /**
20: * @dev Constructs a FixedProxy contract with the given implementation address.
21: * @param implementationAddress The address of the implementation contract
22: */
23: constructor(address implementationAddress) {
24: implementation = implementationAddress;
25: }
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol';
6: import { IERC20 } from '../../../gmp-sdk/interfaces/IERC20.sol';
7:
8: import { SafeTokenTransferFrom, SafeTokenTransfer } from '../../../gmp-sdk/util/SafeTransfer.sol';
9:
10: /**
11: * @title TokenManagerLockUnlock
12: * @notice This contract is an implementation of TokenManager that locks and unlocks a specific token on behalf of the interchain token service.
13: * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods.
14: * It uses the Axelar SDK to safely transfer tokens.
15: */
16: contract TokenManagerLockUnlock is TokenManagerAddressStorage {
17: /**
18: * @dev Constructs an instance of TokenManagerLockUnlock. Calls the constructor
19: * of TokenManagerAddressStorage which calls the constructor of TokenManager.
20: * @param interchainTokenService_ The address of the interchain token service contract
21: */
22: constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {}
23:
24: function implementationType() external pure returns (uint256) {
25: return 0;
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IDistributable } from '../interfaces/IDistributable.sol';
6:
7: /**
8: * @title Distributable Contract
9: * @dev A contract module which provides a basic access control mechanism, where
10: * there is an account (a distributor) that can be granted exclusive access to
11: * specific functions. This module is used through inheritance.
12: */
13: contract Distributable is IDistributable {
14: // uint256(keccak256('distributor')) - 1
15: uint256 internal constant DISTRIBUTOR_SLOT = 0x71c5a35e45a25c49e8f747acd4bcb869814b3d104c492d2554f4c46e12371f56;
16:
17: /**
18: * @dev Throws a NotDistributor custom eror if called by any account other than the distributor.
19: */
20: modifier onlyDistributor() {
21: if (distributor() != msg.sender) revert NotDistributor();
22: _;
23: }
24:
25: /**
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Implementation.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IImplementation } from '../interfaces/IImplementation.sol';
6:
7: /**
8: * @title Implementation
9: * @notice This contract serves as a base for other contracts and enforces a proxy-first access restriction.
10: * @dev Derived contracts must implement the setup function.
11: */
12: abstract contract Implementation is IImplementation {
13: address private immutable implementationAddress;
14:
15: /**
16: * @dev Contract constructor that sets the implementation address to the address of this contract.
17: */
18: constructor() {
19: implementationAddress = address(this);
20: }
21:
22: /**
23: * @dev Modifier to require the caller to be the proxy contract.
24: * Reverts if the caller is the current contract (i.e., the implementation contract itself).
25: */
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { Create3Deployer } from '../../gmp-sdk/deploy/Create3Deployer.sol';
6:
7: import { ITokenManagerDeployer } from '../interfaces/ITokenManagerDeployer.sol';
8:
9: import { TokenManagerProxy } from '../proxies/TokenManagerProxy.sol';
10:
11: /**
12: * @title TokenManagerDeployer
13: * @notice This contract is used to deploy new instances of the TokenManagerProxy contract.
14: */
15: contract TokenManagerDeployer is ITokenManagerDeployer {
16: Create3Deployer public immutable deployer;
17:
18: /**
19: * @notice Constructor for the TokenManagerDeployer contract
20: * @param deployer_ Address of the Create3Deployer contract
21: */
22: constructor(address deployer_) {
23: if (deployer_ == address(0)) revert AddressZero();
24: deployer = Create3Deployer(deployer_);
25: }
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { ITimeLock } from '../interfaces/ITimeLock.sol';
6:
7: /**
8: * @title TimeLock
9: * @dev A contract that enables function execution after a certain time has passed.
10: * Implements the {ITimeLock} interface.
11: */
12: contract TimeLock is ITimeLock {
13: bytes32 internal constant PREFIX_TIME_LOCK = keccak256('time-lock');
14:
15: uint256 internal immutable _minimumTimeLockDelay;
16:
17: /**
18: * @notice The constructor for the TimeLock.
19: * @param minimumTimeDelay The minimum time delay (in secs) that must pass for the TimeLock to be executed
20: */
21: constructor(uint256 minimumTimeDelay) {
22: _minimumTimeLockDelay = minimumTimeDelay;
23: }
24:
25: /**
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IInterchainToken } from './IInterchainToken.sol';
6: import { IDistributable } from './IDistributable.sol';
7: import { IERC20BurnableMintable } from './IERC20BurnableMintable.sol';
8:
9: /**
10: * @title StandardizedToken
11: * @notice This contract implements a standardized token which extends InterchainToken functionality.
12: * This contract also inherits Distributable and Implementation logic.
13: */
14: interface IStandardizedToken is IInterchainToken, IDistributable, IERC20BurnableMintable {
15: /**
16: * @notice Returns the contract id, which a proxy can check to ensure no false implementation was used.
17: */
18: function contractId() external view returns (bytes32);
19:
20: /**
21: * @notice Called by the proxy to setup itself.
22: * @dev This should be hidden by the proxy.
23: * @param params the data to be used for the initialization.
24: */
25: function setup(bytes calldata params) external;
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interfaces/IFlowLimit.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: interface IFlowLimit {
6: error FlowLimitExceeded();
7:
8: event FlowLimitSet(uint256 flowLimit);
9:
10: /**
11: * @notice Returns the current flow limit
12: * @return flowLimit The current flow limit value
13: */
14: function getFlowLimit() external view returns (uint256 flowLimit);
15:
16: /**
17: * @notice Returns the current flow out amount
18: * @return flowOutAmount The current flow out amount
19: */
20: function getFlowOutAmount() external view returns (uint256 flowOutAmount);
21:
22: /**
23: * @notice Returns the current flow in amount
24: * @return flowInAmount The current flow in amount
25: */
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IInterchainGovernance } from './IInterchainGovernance.sol';
6: import { IMultisigBase } from './IMultisigBase.sol';
7:
8: /**
9: * @title IAxelarServiceGovernance Interface
10: * @dev This interface extends IInterchainGovernance and IMultisigBase for multisig proposal actions
11: */
12: interface IAxelarServiceGovernance is IMultisigBase, IInterchainGovernance {
13: error NotApproved();
14:
15: event MultisigApproved(bytes32 indexed proposalHash, address indexed targetContract, bytes callData, uint256 nativeValue);
16: event MultisigCancelled(bytes32 indexed proposalHash, address indexed targetContract, bytes callData, uint256 nativeValue);
17: event MultisigExecuted(bytes32 indexed proposalHash, address indexed targetContract, bytes callData, uint256 nativeValue);
18:
19: /**
20: * @notice Executes a multisig proposal
21: * @param targetContract The target address the proposal will call
22: * @param callData The data that encodes the function and arguments to call on the target contract
23: */
24: function executeMultisigProposal(
25: address targetContract,
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { AxelarExecutable } from '../../gmp-sdk/executable/AxelarExecutable.sol';
6: import { TimeLock } from '../../gmp-sdk/util/TimeLock.sol';
7: import { IInterchainGovernance } from '../interfaces/IInterchainGovernance.sol';
8: import { Caller } from '../util/Caller.sol';
9:
10: /**
11: * @title Interchain Governance contract
12: * @notice This contract handles cross-chain governance actions. It includes functionality
13: * to create, cancel, and execute governance proposals.
14: */
15: contract InterchainGovernance is AxelarExecutable, TimeLock, Caller, IInterchainGovernance {
16: enum GovernanceCommand {
17: ScheduleTimeLockProposal,
18: CancelTimeLockProposal
19: }
20:
21: string public governanceChain;
22: string public governanceAddress;
23: bytes32 public immutable governanceChainHash;
24: bytes32 public immutable governanceAddressHash;
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IAxelarExecutable } from '../../gmp-sdk/interfaces/IAxelarExecutable.sol';
6: import { ICaller } from './ICaller.sol';
7:
8: /**
9: * @title IInterchainGovernance Interface
10: * @notice This interface extends IAxelarExecutable for interchain governance mechanisms.
11: */
12: interface IInterchainGovernance is IAxelarExecutable, ICaller {
13: error NotGovernance();
14: error InvalidCommand();
15: error InvalidTarget();
16: error TokenNotSupported();
17:
18: event ProposalScheduled(bytes32 indexed proposalHash, address indexed target, bytes callData, uint256 value, uint256 indexed eta);
19: event ProposalCancelled(bytes32 indexed proposalHash, address indexed target, bytes callData, uint256 value, uint256 indexed eta);
20: event ProposalExecuted(bytes32 indexed proposalHash, address indexed target, bytes callData, uint256 value, uint256 indexed timestamp);
21:
22: /**
23: * @notice Returns the name of the governance chain.
24: * @return string The name of the governance chain
25: */
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IProxy } from './IProxy.sol';
6:
7: // General interface for upgradable contracts
8: interface IInitProxy is IProxy {
9: function init(
10: address implementationAddress,
11: address newOwner,
12: bytes memory params
13: ) external;
14: }
15:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IMultisigBase } from '../interfaces/IMultisigBase.sol';
6:
7: /**
8: * @title MultisigBase Contract
9: * @notice This contract implements a custom multisignature wallet where transactions must be confirmed by a
10: * threshold of signers. The signers and threshold may be updated every `epoch`.
11: */
12: contract MultisigBase is IMultisigBase {
13: struct Voting {
14: uint256 voteCount;
15: mapping(address => bool) hasVoted;
16: }
17:
18: struct Signers {
19: address[] accounts;
20: uint256 threshold;
21: mapping(address => bool) isSigner;
22: }
23:
24: Signers public signers;
25: uint256 public signerEpoch;
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IInitProxy } from '../interfaces/IInitProxy.sol';
6: import { IUpgradable } from '../interfaces/IUpgradable.sol';
7: import { BaseProxy } from './BaseProxy.sol';
8:
9: /**
10: * @title InitProxy Contract
11: * @notice A proxy contract that can be initialized to use a specified implementation and owner. Inherits from BaseProxy
12: * and implements the IInitProxy interface.
13: * @dev This proxy is constructed empty and then later initialized with the implementation contract address, new owner address,
14: * and any optional setup parameters.
15: */
16: contract InitProxy is BaseProxy, IInitProxy {
17: /**
18: * @dev Initializes the contract and sets the caller as the owner of the contract.
19: */
20: constructor() {
21: assembly {
22: sstore(_OWNER_SLOT, caller())
23: }
24: }
25:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { InterchainCalls } from '../lib/InterchainCalls.sol';
6:
7: interface IInterchainProposalSender {
8: // An error emitted when the given gas is invalid
9: error InvalidFee();
10:
11: /**
12: * @dev Broadcast the proposal to be executed at multiple destination chains
13: * @param calls An array of calls to be executed at the destination chain
14: */
15: function sendProposals(InterchainCalls.InterchainCall[] memory calls) external payable;
16:
17: /**
18: * @dev Broadcast the proposal to be executed at single destination chain
19: * @param destinationChain destination chain
20: * @param destinationContract destination contract
21: * @param calls An array of calls to be executed at the destination chain
22: */
23: function sendProposal(
24: string calldata destinationChain,
25: string calldata destinationContract,
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title StandardizedTokenProxy
7: * @dev Proxy contract for StandardizedToken contracts. Inherits from FixedProxy and implements IStandardizedTokenProxy.
8: */
9: interface IStandardizedTokenProxy {
10: /**
11: * @notice Returns the contract id, which a proxy can check to ensure no false implementation was used.
12: */
13: function contractId() external view returns (bytes32);
14: }
15:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title IRemoteAddressValidator
7: * @dev Manages and validates remote addresses, keeps track of addresses supported by the Axelar gateway contract
8: */
9: interface IRemoteAddressValidator {
10: error ZeroAddress();
11: error LengthMismatch();
12: error ZeroStringLength();
13:
14: event TrustedAddressAdded(string souceChain, string sourceAddress);
15: event TrustedAddressRemoved(string souceChain);
16: event GatewaySupportedChainAdded(string chain);
17: event GatewaySupportedChainRemoved(string chain);
18:
19: /**
20: * @dev Validates that the sender is a valid interchain token service address
21: * @param sourceChain Source chain of the transaction
22: * @param sourceAddress Source address of the transaction
23: * @return bool true if the sender is validated, false otherwise
24: */
25: function validateSender(string calldata sourceChain, string calldata sourceAddress) external view returns (bool);
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IAxelarGateway } from '../../gmp-sdk/interfaces/IAxelarGateway.sol';
6: import { IAxelarGasService } from '../../gmp-sdk/interfaces/IAxelarGasService.sol';
7: import { AxelarExecutable } from '../../gmp-sdk/executable/AxelarExecutable.sol';
8: import { SafeTokenTransferFrom } from '../../gmp-sdk/util/SafeTransfer.sol';
9: import { IERC20 } from '../../gmp-sdk/interfaces/IERC20.sol';
10:
11: import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol';
12: import { ITokenManagerDeployer } from '../interfaces/ITokenManagerDeployer.sol';
13: import { IStandardizedTokenDeployer } from '../interfaces/IStandardizedTokenDeployer.sol';
14: import { IRemoteAddressValidator } from '../interfaces/IRemoteAddressValidator.sol';
15: import { IInterchainTokenExpressExecutable } from '../interfaces/IInterchainTokenExpressExecutable.sol';
16: import { ITokenManager } from '../interfaces/ITokenManager.sol';
17: import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol';
18: import { IERC20Named } from '../interfaces/IERC20Named.sol';
19:
20: import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol';
21: import { StringToBytes32, Bytes32ToString } from '../../gmp-sdk/util/Bytes32String.sol';
22:
23: import { Upgradable } from '../../gmp-sdk/upgradable/Upgradable.sol';
24: import { Create3Deployer } from '../../gmp-sdk/deploy/Create3Deployer.sol';
25:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.9;
4:
5: import { SafeTokenCall, SafeTokenTransfer, SafeTokenTransferFrom } from '../gmp-sdk/util/SafeTransfer.sol';
6: import { IERC20 } from '../gmp-sdk/interfaces/IERC20.sol';
7: import { IAxelarGateway } from './interfaces/IAxelarGateway.sol';
8: import { IGovernable } from './interfaces/IGovernable.sol';
9: import { IAxelarAuth } from './interfaces/IAxelarAuth.sol';
10: import { IBurnableMintableCappedERC20 } from './interfaces/IBurnableMintableCappedERC20.sol';
11: import { ITokenDeployer } from './interfaces/ITokenDeployer.sol';
12:
13: import { ECDSA } from './ECDSA.sol';
14: import { DepositHandler } from './DepositHandler.sol';
15: import { AdminMultisigBase } from './AdminMultisigBase.sol';
16:
17: contract AxelarGateway is IAxelarGateway, IGovernable, AdminMultisigBase {
18: using SafeTokenCall for IERC20;
19: using SafeTokenTransfer for IERC20;
20: using SafeTokenTransferFrom for IERC20;
21:
22: error InvalidImplementation();
23:
24: enum TokenType {
25: InternalBurnable,
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { Create3Deployer } from '../../gmp-sdk/deploy/Create3Deployer.sol';
6:
7: /**
8: * @title ITokenManagerDeployer
9: * @notice This contract is used to deploy new instances of the TokenManagerProxy contract.
10: */
11: interface ITokenManagerDeployer {
12: error AddressZero();
13: error TokenManagerDeploymentFailed();
14:
15: /**
16: * @notice Getter for the Create3Deployer.
17: */
18: function deployer() external view returns (Create3Deployer);
19:
20: /**
21: * @notice Deploys a new instance of the TokenManagerProxy contract
22: * @param tokenId The unique identifier for the token
23: * @param implementationType Token manager implementation type
24: * @param params Additional parameters used in the setup of the token manager
25: */
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol';
6: import { IERC20BurnableMintable } from '../../interfaces/IERC20BurnableMintable.sol';
7:
8: import { IERC20 } from '../../../gmp-sdk/interfaces/IERC20.sol';
9: import { SafeTokenCall } from '../../../gmp-sdk/util/SafeTransfer.sol';
10:
11: /**
12: * @title TokenManagerMintBurn
13: * @notice This contract is an implementation of TokenManager that mints and burns a specific token on behalf of the interchain token service.
14: * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods.
15: * It uses the Axelar SDK to safely transfer tokens.
16: */
17: contract TokenManagerMintBurn is TokenManagerAddressStorage {
18: /**
19: * @dev Constructs an instance of TokenManagerMintBurn. Calls the constructor
20: * of TokenManagerAddressStorage which calls the constructor of TokenManager.
21: * @param interchainTokenService_ The address of the interchain token service contract
22: */
23: constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {}
24:
25: function implementationType() external pure returns (uint256) {
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IOperatable } from '../interfaces/IOperatable.sol';
6:
7: /**
8: * @title Operatable Contract
9: * @dev A contract module which provides a basic access control mechanism, where
10: * there is an account (an operator) that can be granted exclusive access to
11: * specific functions. This module is used through inheritance.
12: */
13: contract Operatable is IOperatable {
14: // uint256(keccak256('operator')) - 1
15: uint256 internal constant OPERATOR_SLOT = 0xf23ec0bb4210edd5cba85afd05127efcd2fc6a781bfed49188da1081670b22d7;
16:
17: /**
18: * @dev Throws a NotOperator custom error if called by any account other than the operator.
19: */
20: modifier onlyOperator() {
21: if (operator() != msg.sender) revert NotOperator();
22: _;
23: }
24:
25: /**
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title ITimeLock
7: * @dev Interface for a TimeLock that enables function execution after a certain time has passed.
8: */
9: interface ITimeLock {
10: error InvalidTimeLockHash();
11: error TimeLockAlreadyScheduled();
12: error TimeLockNotReady();
13:
14: /**
15: * @notice Returns a minimum time delay at which the TimeLock may be scheduled.
16: * @return uint Minimum scheduling delay time (in secs) from the current block timestamp
17: */
18: function minimumTimeLockDelay() external view returns (uint256);
19:
20: /**
21: * @notice Returns the timestamp after which the TimeLock may be executed.
22: * @param hash The hash of the timelock
23: * @return uint The timestamp after which the timelock with the given hash can be executed
24: */
25: function getTimeLock(bytes32 hash) external view returns (uint256);
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol';
6: import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol';
7:
8: /**
9: * @title TokenManagerProxy
10: * @dev This contract is a proxy for token manager contracts. It implements ITokenManagerProxy and
11: * inherits from FixedProxy from the gmp sdk repo
12: */
13: contract TokenManagerProxy is ITokenManagerProxy {
14: IInterchainTokenService public immutable interchainTokenServiceAddress;
15: uint256 public immutable implementationType;
16: bytes32 public immutable tokenId;
17:
18: /**
19: * @dev Constructs the TokenManagerProxy contract.
20: * @param interchainTokenServiceAddress_ The address of the interchain token service
21: * @param implementationType_ The token manager type
22: * @param tokenId_ The identifier for the token
23: * @param params The initialization parameters for the token manager contract
24: */
25: constructor(
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IInterchainToken } from '../interfaces/IInterchainToken.sol';
6: import { ITokenManager } from '../interfaces/ITokenManager.sol';
7: import { ERC20 } from '../token-implementations/ERC20.sol';
8:
9: /**
10: * @title An example implementation of the IInterchainToken.
11: * @notice The implementation ERC20 can be done in any way, however this example assumes that an _approve internal function exists
12: * that can be used to create approvals, and that `allowance` is a mapping.
13: * @dev You can skip the `tokenManagerRequiresApproval()` function altogether if you know what it should return for your token.
14: */
15: abstract contract InterchainToken is IInterchainToken, ERC20 {
16: /**
17: * @notice Getter for the tokenManager used for this token.
18: * @dev Needs to be overwitten.
19: * @return tokenManager the TokenManager called to facilitate cross chain transfers.
20: */
21: function getTokenManager() public view virtual returns (ITokenManager tokenManager);
22:
23: /**
24: * @notice Getter function specifiying if the tokenManager requires approval to facilitate cross-chain transfers.
25: * Usually, only mint/burn tokenManagers do not need approval.
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { Create3Deployer } from '../../gmp-sdk/deploy/Create3Deployer.sol';
6:
7: /**
8: * @title IStandardizedTokenDeployer
9: * @notice This contract is used to deploy new instances of the StandardizedTokenProxy contract.
10: */
11: interface IStandardizedTokenDeployer {
12: error AddressZero();
13: error TokenDeploymentFailed();
14:
15: /**
16: * @notice Getter for the Create3Deployer.
17: */
18: function deployer() external view returns (Create3Deployer);
19:
20: /**
21: * @notice Deploys a new instance of the StandardizedTokenProxy contract
22: * @param salt The salt used by Create3Deployer
23: * @param tokenManager Address of the token manager
24: * @param distributor Address of the distributor
25: * @param name Name of the token
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title IMultisigBase Interface
7: * @notice An interface defining the base operations for a multisignature contract.
8: */
9: interface IMultisigBase {
10: error NotSigner();
11: error AlreadyVoted();
12: error InvalidSigners();
13: error InvalidSignerThreshold();
14: error DuplicateSigner(address account);
15:
16: /**********\
17: |* Events *|
18: \**********/
19:
20: event MultisigOperationExecuted(bytes32 indexed operationHash);
21:
22: event SignersRotated(address[] newAccounts, uint256 newThreshold);
23:
24: /***********\
25: |* Getters *|
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/interfaces/IProxy.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: // General interface for upgradable contracts
6: interface IProxy {
7: error InvalidOwner();
8: error InvalidImplementation();
9: error SetupFailed();
10: error NotOwner();
11: error AlreadyInitialized();
12:
13: function implementation() external view returns (address implementation_);
14:
15: function setup(bytes calldata setupParams) external;
16: }
17:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Caller.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { ICaller } from '../interfaces/ICaller.sol';
6:
7: contract Caller is ICaller {
8: /**
9: * @dev Calls a target address with specified calldata and optionally sends value.
10: */
11: function _call(
12: address target,
13: bytes calldata callData,
14: uint256 nativeValue
15: ) internal {
16: if (nativeValue > address(this).balance) revert InsufficientBalance();
17:
18: (bool success, ) = target.call{ value: nativeValue }(callData);
19: if (!success) {
20: revert ExecutionFailed();
21: }
22: }
23: }
24:
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/Proxy.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IProxy } from '../interfaces/IProxy.sol';
6: import { IUpgradable } from '../interfaces/IUpgradable.sol';
7: import { BaseProxy } from './BaseProxy.sol';
8:
9: /**
10: * @title Proxy Contract
11: * @notice A proxy contract that delegates calls to a designated implementation contract. Inherits from BaseProxy.
12: * @dev The constructor takes in the address of the implementation contract, the owner address, and any optional setup
13: * parameters for the implementation contract.
14: */
15: contract Proxy is BaseProxy {
16: /**
17: * @notice Constructs the proxy contract with a the implementation address, owner address, and optional setup parameters.
18: * @param implementationAddress The address of the implementation contract
19: * @param owner The owner address
20: * @param setupParams Optional parameters to setup the implementation contract
21: * @dev The constructor verifies that the owner address is not the zero address and that the contract ID of the implementation is valid.
22: * It then stores the implementation address and owner address in their designated storage slots and calls the setup function on the
23: * implementation (if setup params exist).
24: */
25: constructor(
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interfaces/IPausable.sol#L1-L1
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title Pausable
7: * @notice This contract provides a mechanism to halt the execution of specific functions
8: * if a pause condition is activated.
9: */
10: interface IPausable {
11: event PausedSet(bool paused);
12:
13: error Paused();
14:
15: /**
16: * @notice Check if the contract is paused
17: * @return paused A boolean representing the pause status. True if paused, false otherwise.
18: */
19: function isPaused() external view returns (bool);
20: }
21:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: interface IDistributable {
6: error NotDistributor();
7:
8: event DistributorChanged(address distributor);
9:
10: /**
11: * @notice Get the address of the distributor
12: * @return distributor of the distributor
13: */
14: function distributor() external view returns (address distributor);
15:
16: /**
17: * @notice Change the distributor of the contract
18: * @dev Can only be called by the current distributor
19: * @param distributor The address of the new distributor
20: */
21: function setDistributor(address distributor) external;
22: }
23:
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IERC20BurnableMintable } from '../interfaces/IERC20BurnableMintable.sol';
6:
7: import { InterchainToken } from '../interchain-token/InterchainToken.sol';
8: import { ERC20Permit } from '../token-implementations/ERC20Permit.sol';
9: import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol';
10: import { ITokenManager } from '../interfaces/ITokenManager.sol';
11: import { Implementation } from '../utils/Implementation.sol';
12: import { Distributable } from '../utils/Distributable.sol';
13:
14: /**
15: * @title StandardizedToken
16: * @notice This contract implements a standardized token which extends InterchainToken functionality.
17: * This contract also inherits Distributable and Implementation logic.
18: */
19: abstract contract StandardizedToken is InterchainToken, ERC20Permit, Implementation, Distributable {
20: using AddressBytesUtils for bytes;
21:
22: address public tokenManager;
23: string public name;
24: string public symbol;
25: uint8 public decimals;
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IProxy } from '../interfaces/IProxy.sol';
6:
7: /**
8: * @title BaseProxy Contract
9: * @dev This abstract contract implements a basic proxy that stores an implementation address. Fallback function
10: * calls are delegated to the implementation. This contract is meant to be inherited by other proxy contracts.
11: */
12: abstract contract BaseProxy is IProxy {
13: // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
14: bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
15: // keccak256('owner')
16: bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0;
17:
18: /**
19: * @dev Returns the current implementation address.
20: * @return implementation_ The address of the current implementation contract
21: */
22: function implementation() public view virtual returns (address implementation_) {
23: assembly {
24: implementation_ := sload(_IMPLEMENTATION_SLOT)
25: }
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { TokenManager } from '../TokenManager.sol';
6: import { IERC20 } from '../../../gmp-sdk/interfaces/IERC20.sol';
7: import { IAxelarGateway } from '../../../gmp-sdk/interfaces/IAxelarGateway.sol';
8:
9: /**
10: * @title TokenManagerAddressStorage
11: * @notice This contract extends the TokenManager contract and provides additional functionality to store and retrieve
12: * the token address using a predetermined storage slot
13: */
14: abstract contract TokenManagerAddressStorage is TokenManager {
15: /**
16: * @dev Creates an instance of the TokenManagerAddressStorage contract.
17: * @param interchainTokenService_ The address of the interchain token service contract
18: */
19: constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {}
20:
21: // uint256(keccak256('token-address')) - 1
22: uint256 internal constant TOKEN_ADDRESS_SLOT = 0xc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42ba;
23:
24: /**
25: * @dev Reads the stored token address from the predetermined storage slot
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol';
6: import { IERC20 } from '../../../gmp-sdk/interfaces/IERC20.sol';
7:
8: import { SafeTokenTransferFrom } from '../../../gmp-sdk/util/SafeTransfer.sol';
9:
10: /**
11: * @title TokenManagerLiquidityPool
12: * @notice This contract is a an implementation of TokenManager that stores all tokens in a separate liquity pool
13: * rather than within itself.
14: * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods.
15: * It uses the Axelar SDK to safely transfer tokens.
16: */
17: contract TokenManagerLiquidityPool is TokenManagerAddressStorage {
18: // uint256(keccak256('liquidity-pool-slot')) - 1
19: uint256 internal constant LIQUIDITY_POOL_SLOT = 0x8e02741a3381812d092c5689c9fc701c5185c1742fdf7954c4c4472be4cc4807;
20:
21: /**
22: * @dev Constructs an instance of TokenManagerLiquidityPool. Calls the constructor
23: * of TokenManagerAddressStorage which calls the constructor of TokenManager.
24: * @param interchainTokenService_ The address of the interchain token service contract
25: */
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { FixedProxy } from '../../gmp-sdk/upgradable/FixedProxy.sol';
6: import { IStandardizedToken } from '../interfaces/IStandardizedToken.sol';
7: import { IStandardizedTokenProxy } from '../interfaces/IStandardizedTokenProxy.sol';
8:
9: /**
10: * @title StandardizedTokenProxy
11: * @dev Proxy contract for StandardizedToken contracts. Inherits from FixedProxy and implements IStandardizedTokenProxy.
12: */
13: contract StandardizedTokenProxy is FixedProxy, IStandardizedTokenProxy {
14: bytes32 private constant CONTRACT_ID = keccak256('standardized-token');
15:
16: /**
17: * @dev Constructs the StandardizedTokenProxy contract.
18: * @param implementationAddress Address of the StandardizedToken implementation
19: * @param params Initialization parameters for the StandardizedToken contract
20: */
21: constructor(address implementationAddress, bytes memory params) FixedProxy(implementationAddress) {
22: if (IStandardizedToken(implementationAddress).contractId() != CONTRACT_ID) revert InvalidImplementation();
23:
24: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IStandardizedToken.setup.selector, params));
25: if (!success) revert SetupFailed();
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: interface IExpressCallHandler {
6: error AlreadyExpressCalled();
7: error SameDestinationAsCaller();
8:
9: event ExpressReceive(
10: bytes32 indexed tokenId,
11: address indexed destinationAddress,
12: uint256 amount,
13: bytes32 indexed sendHash,
14: address expressCaller
15: );
16: event ExpressExecutionFulfilled(
17: bytes32 indexed tokenId,
18: address indexed destinationAddress,
19: uint256 amount,
20: bytes32 indexed sendHash,
21: address expressCaller
22: );
23:
24: event ExpressReceiveWithData(
25: bytes32 indexed tokenId,
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IExpressCallHandler } from '../interfaces/IExpressCallHandler.sol';
6:
7: /**
8: * @title ExpressCallHandler
9: * @dev Integrates the interchain token service with the GMP express service by providing methods to handle express calls for
10: * token transfers and token transfers with contract calls between chains. Implements the IExpressCallHandler interface.
11: */
12: contract ExpressCallHandler is IExpressCallHandler {
13: // uint256(keccak256('prefix-express-give-token'));
14: uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN = 0x67c7b41c1cb0375e36084c4ec399d005168e83425fa471b9224f6115af865619;
15: // uint256(keccak256('prefix-express-give-token-with-data'));
16: uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA = 0x3e607cc12a253b1d9f677a03d298ad869a90a8ba4bd0fb5739e7d79db7cdeaad;
17:
18: /**
19: * @notice Calculates the unique slot for a given express token transfer.
20: * @param tokenId The ID of the token being sent
21: * @param destinationAddress The address of the recipient
22: * @param amount The amount of tokens to be sent
23: * @param commandId The unique hash for this token transfer
24: * @return slot The calculated slot for this token transfer
25: */
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { IAxelarServiceGovernance } from '../interfaces/IAxelarServiceGovernance.sol';
6: import { InterchainGovernance } from './InterchainGovernance.sol';
7: import { MultisigBase } from '../auth/MultisigBase.sol';
8:
9: /**
10: * @title AxelarServiceGovernance Contract
11: * @dev This contract is part of the Axelar Governance system, it inherits the Interchain Governance contract
12: * with added functionality to approve and execute multisig proposals.
13: */
14: contract AxelarServiceGovernance is InterchainGovernance, MultisigBase, IAxelarServiceGovernance {
15: enum ServiceGovernanceCommand {
16: ScheduleTimeLockProposal,
17: CancelTimeLockProposal,
18: ApproveMultisigProposal,
19: CancelMultisigApproval
20: }
21:
22: mapping(bytes32 => bool) public multisigApprovals;
23:
24: /**
25: * @notice Initializes the contract.
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: import { FinalProxy } from '../../gmp-sdk/upgradable/FinalProxy.sol';
6:
7: /**
8: * @title InterchainTokenServiceProxy
9: * @dev Proxy contract for interchain token service contracts. Inherits from the FinalProxy contract.
10: */
11: contract InterchainTokenServiceProxy is FinalProxy {
12: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service');
13:
14: /**
15: * @dev Constructs the InterchainTokenServiceProxy contract.
16: * @param implementationAddress Address of the interchain token service implementation
17: * @param owner Address of the owner of the proxy
18: */
19: constructor(
20: address implementationAddress,
21: address owner,
22: address operator
23: ) FinalProxy(implementationAddress, owner, abi.encodePacked(operator)) {}
24:
25: /**
1: // SPDX-License-Identifier: MIT
2:
3: pragma solidity ^0.8.0;
4:
5: /**
6: * @title TokenManagerProxy
7: * @dev This contract is a proxy for token manager contracts. It implements ITokenManagerProxy and
8: * inherits from FixedProxy from the gmp sdk repo
9: */
10: interface ITokenManagerProxy {
11: error ImplementationLookupFailed();
12: error SetupFailed();
13:
14: /**
15: * @notice Returns implementation type of this token manager
16: */
17: function implementationType() external view returns (uint256);
18:
19: /**
20: * @notice Returns the address of the current implementation.
21: * @return impl The address of the current implementation
22: */
23: function implementation() external view returns (address);
24:
25: /**
9
External calls in Solidity are costly in terms of gas usage. This can significantly impact contract efficiency and cost. Functions that make repetitive calls to fetch the same data from other contracts can cause unnecessary gas expenditure. To optimize this, it's advisable to store the returned value of these function calls in a state variable, essentially caching the data. This data can be updated at regular intervals or under specific conditions instead of fetching it from the external contract on every invocation. Be sure to analyze the frequency of data change in the external contract to balance data freshness with gas efficiency when implementing caching.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L149-L173
149: function _rotateSigners(address[] memory newAccounts, uint256 newThreshold) internal {
150: uint256 length = signers.accounts.length;
151:
152:
153: for (uint256 i; i < length; ++i) {
154: signers.isSigner[signers.accounts[i]] = false;
155: }
156:
157: length = newAccounts.length;
158:
159: if (newThreshold > length) revert InvalidSigners(); // <= FOUND
160:
161: if (newThreshold == 0) revert InvalidSignerThreshold();
162:
163: ++signerEpoch;
164:
165: signers.accounts = newAccounts;
166: signers.threshold = newThreshold;
167:
168: for (uint256 i; i < length; ++i) {
169: address account = newAccounts[i];
170:
171:
172: if (signers.isSigner[account]) revert DuplicateSigner(account);
173: if (account == address(0)) revert InvalidSigners(); // <= FOUND
174:
175: signers.isSigner[account] = true;
176: }
177:
178: emit SignersRotated(newAccounts, newThreshold);
179: }
35: function init(
36: address implementationAddress,
37: address newOwner,
38: bytes memory params
39: ) external {
40: address owner;
41:
42: assembly {
43: owner := sload(_OWNER_SLOT)
44: }
45:
46: if (msg.sender != owner) revert NotOwner();
47: if (implementation() != address(0)) revert AlreadyInitialized(); // <= FOUND
48:
49: bytes32 id = contractId(); // <= FOUND
50: if (id != bytes32(0) && IUpgradable(implementationAddress).contractId() != id) revert InvalidImplementation(); // <= FOUND
51:
52: assembly {
53: sstore(_IMPLEMENTATION_SLOT, implementationAddress)
54: sstore(_OWNER_SLOT, newOwner)
55: }
56:
57: if (params.length != 0) {
58: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IUpgradable.setup.selector, params));
59: if (!success) revert SetupFailed();
60: }
61: }
37: function implementation() public view override(BaseProxy, IProxy) returns (address implementation_) { // <= FOUND
38: implementation_ = _finalImplementation();
39: if (implementation_ == address(0)) {
40: implementation_ = super.implementation(); // <= FOUND
41: }
42: }
83: function addTrustedAddress(string memory chain, string memory addr) public onlyOwner {
84: if (bytes(chain).length == 0) revert ZeroStringLength(); // <= FOUND
85: if (bytes(addr).length == 0) revert ZeroStringLength(); // <= FOUND
86: remoteAddressHashes[chain] = keccak256(bytes(_lowerCase(addr)));
87: remoteAddresses[chain] = addr;
88: emit TrustedAddressAdded(chain, addr);
89: }
1
Private functions which are only called once can be inlined to save GAS.
Findings are labeled with ' <= FOUND'
Click to show findings
104: function revertIfInvalidFee(InterchainCalls.InterchainCall[] calldata interchainCalls) private // <= FOUND
10
Bitmaps in Solidity are essentially a way of representing a set of boolean values within an integer type variable such as uint256
. Each bit in the integer represents a true or false value (1 or 0), thus allowing efficient storage of multiple boolean values.
Bitmaps can save gas in the Ethereum network because they condense a lot of information into a small amount of storage. In Ethereum, storage is one of the most significant costs in terms of gas usage. By reducing the amount of storage space needed, you can potentially save on gas fees.
Here's a quick comparison:
If you were to represent 256 different boolean values in the traditional way, you would have to declare 256 different bool
variables. Given that each bool
occupies a storage slot and each storage slot costs 20,000 gas to initialize, you would end up paying a considerable amount of gas.
On the other hand, if you were to use a bitmap, you could store these 256 boolean values within a single uint256
variable. In other words, you'd only pay for a single storage slot, resulting in significant gas savings.
However, it's important to note that while bitmaps can provide gas efficiencies, they do add complexity to the code, making it harder to read and maintain. Also, using bitmaps is efficient only when dealing with a large number of boolean variables that are frequently changed or accessed together.
In contrast, the straightforward counterpart to bitmaps would be using arrays or mappings to store boolean values, with each bool
value occupying its own storage slot. This approach is simpler and more readable but could potentially be more expensive in terms of gas usage.
Findings are labeled with ' <= FOUND'
Click to show findings
97: multisigApprovals[proposalHash] = true; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L53-L53
53: voting.hasVoted[msg.sender] = true; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L175-L175
175: signers.isSigner[account] = true; // <= FOUND
110: supportedByGateway[chainName] = true; // <= FOUND
57: multisigApprovals[proposalHash] = false; // <= FOUND
102: multisigApprovals[proposalHash] = false; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L71-L71
71: voting.hasVoted[signers.accounts[i]] = false; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L154-L154
154: signers.isSigner[signers.accounts[i]] = false; // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L364-L364
364: allowOperatorshipTransfer = false; // <= FOUND
123: supportedByGateway[chainName] = false; // <= FOUND
38
From a gas standpoint, the assembly version of the keccak256 hashing function can be more efficient than the high-level Solidity version. This is because Solidity has additional overhead when handling function calls and memory management, which can increase the gas cost.
Findings are labeled with ' <= FOUND'
Click to show findings
41: governanceChainHash = keccak256(bytes(governanceChain_)); // <= FOUND
42: governanceAddressHash = keccak256(bytes(governanceAddress_)); // <= FOUND
73: bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L47-L47
47: bytes32 topic = keccak256(msg.data); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L13-L13
13: bytes32 internal constant PREFIX_TIME_LOCK = keccak256('time-lock'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L93-L93
93: bytes32 key = keccak256(abi.encodePacked(PREFIX_TIME_LOCK, hash)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L44-L44
44: bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L45-L45
45: bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L46-L46
46: bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L47-L47
47: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L48-L48
48: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L49-L49
49: bytes32 internal constant PREFIX_TOKEN_MINT_LIMIT = keccak256('token-mint-limit'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L50-L50
50: bytes32 internal constant PREFIX_TOKEN_MINT_AMOUNT = keccak256('token-mint-amount'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L52-L52
52: bytes32 internal constant SELECTOR_BURN_TOKEN = keccak256('burnToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L53-L53
53: bytes32 internal constant SELECTOR_DEPLOY_TOKEN = keccak256('deployToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L54-L54
54: bytes32 internal constant SELECTOR_MINT_TOKEN = keccak256('mintToken'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L55-L55
55: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL = keccak256('approveContractCall'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L56-L56
56: bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT = keccak256('approveContractCallWithMint'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L57-L57
57: bytes32 internal constant SELECTOR_TRANSFER_OPERATORSHIP = keccak256('transferOperatorship'); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L349-L349
349: bytes32 commandHash = keccak256(abi.encodePacked(commands[i])); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L395-L395
395: bytes32 salt = keccak256(abi.encodePacked(symbol)); // <= FOUND
63: bytes32 newSalt = keccak256(abi.encode(sender, salt)); // <= FOUND
30: bytes32 deploySalt = keccak256(abi.encode(msg.sender, salt)); // <= FOUND
68: bytes32 deploySalt = keccak256(abi.encode(sender, salt)); // <= FOUND
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/Create3.sol#L41-L41
41: bytes32 internal constant DEPLOYER_BYTECODE_HASH = keccak256(type(CreateDeployer).creationCode); // <= FOUND
18: bytes32 internal constant FINAL_IMPLEMENTATION_SALT = keccak256('final-implementation'); // <= FOUND
62: bytes32 internal constant PREFIX_CUSTOM_TOKEN_ID = keccak256('its-custom-token-id'); // <= FOUND
63: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_ID = keccak256('its-standardized-token-id'); // <= FOUND
64: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_SALT = keccak256('its-standardized-token-salt'); // <= FOUND
71: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service'); // <= FOUND
111: chainNameHash = keccak256(bytes(chainName_)); // <= FOUND
203: tokenId = keccak256(abi.encode(PREFIX_STANDARDIZED_TOKEN_ID, chainNameHash, tokenAddress)); // <= FOUND
214: tokenId = keccak256(abi.encode(PREFIX_CUSTOM_TOKEN_ID, sender, salt)); // <= FOUND
12: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator'); // <= FOUND
27: bytes32 private constant CONTRACT_ID = keccak256('standardized-token'); // <= FOUND
30: interchainTokenServiceAddressHash = keccak256(bytes(_lowerCase(interchainTokenServiceAddress.toString()))); // <= FOUND
71: bytes32 sourceAddressHash = keccak256(bytes(sourceAddressLC)); // <= FOUND
86: remoteAddressHashes[chain] = keccak256(bytes(_lowerCase(addr))); // <= FOUND
2
Merging multiple for
loops within a function in Solidity can enhance efficiency and reduce gas costs, especially when they share a common iterating variable or perform related operations. By minimizing redundant iterations over the same data set, execution becomes more cost-effective. However, while merging can optimize gas usage and simplify logic, it may also increase code complexity. Therefore, careful balance between optimization and maintainability is essential, along with thorough testing to ensure the refactored code behaves as expected.
Findings are labeled with ' <= FOUND'
Click to show findings
https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L149-L168
149: function _rotateSigners(address[] memory newAccounts, uint256 newThreshold) internal {
150: uint256 length = signers.accounts.length;
151:
152:
153: for (uint256 i; i < length; ++i) { // <= FOUND
154: signers.isSigner[signers.accounts[i]] = false;
155: }
156:
157: length = newAccounts.length;
158:
159: if (newThreshold > length) revert InvalidSigners();
160:
161: if (newThreshold == 0) revert InvalidSignerThreshold();
162:
163: ++signerEpoch;
164:
165: signers.accounts = newAccounts;
166: signers.threshold = newThreshold;
167:
168: for (uint256 i; i < length; ++i) { // <= FOUND
169: address account = newAccounts[i];
170:
171:
172: if (signers.isSigner[account]) revert DuplicateSigner(account);
173: if (account == address(0)) revert InvalidSigners();
174:
175: signers.isSigner[account] = true;
176: }
177:
178: emit SignersRotated(newAccounts, newThreshold);
179: }
For transparency, the sponsor has provided their input on the H/M findings within this bot report via discord. Their response is below: