Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Module mediator #12

Merged
merged 89 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
bf7c628
[#4] Create mediator interface
akshay-ap Jun 20, 2023
31772a6
[#4] Create SafeProtcolMediator contract
akshay-ap Jun 20, 2023
22338ec
[#4] Create an ownable mediator contract, define mediator interface
akshay-ap Jun 20, 2023
81efd68
[#4] Setup TestExecutor contract
akshay-ap Jun 20, 2023
11fe5d3
[#4] Format *.sol files
akshay-ap Jun 20, 2023
96f2067
[#4] Add test modules
akshay-ap Jun 20, 2023
6546e17
[#4] WIP: Add events, errors, logic in protocol mediator
akshay-ap Jun 20, 2023
4a1dc84
[#4] Format *.sol files
akshay-ap Jun 21, 2023
59c3ae8
[#4] Fix imports
akshay-ap Jun 21, 2023
4aa7ca5
[#4] Add functions to enable/disable modules from mediator
akshay-ap Jun 23, 2023
4c35d13
[#1,#4] Add .solcover.js file
akshay-ap Jun 23, 2023
e026c30
[#4] Add events for enable/disable modules, add getModuleInfo(...) fu…
akshay-ap Jun 23, 2023
b83c7e0
[#4] Add tests for enable/disable module
akshay-ap Jun 23, 2023
d76e769
[#4] Run yarn fmt:sol
akshay-ap Jun 23, 2023
a7d03fb
Merge branch 'feature-#3-create-registry' of github.com:5afe/safe-pro…
akshay-ap Jun 23, 2023
bb6607a
[#4] Fix lint warnings related to imports
akshay-ap Jun 23, 2023
1d7ae7f
[#4] Remove use of nonce from Protocol mediator for module
akshay-ap Jun 23, 2023
a6400a0
[#4] Add bignumber.js as dependency
akshay-ap Jun 26, 2023
728d538
[#4] Update function arguments for test module(s)
akshay-ap Jun 26, 2023
c3581dc
[#4] Allow test executor to receive ethers
akshay-ap Jun 26, 2023
0a897f5
[#4] Add test for executing transaction from a mediator
akshay-ap Jun 26, 2023
abc7d00
[#4] Add event for failed non-root execution, add test case for faile…
akshay-ap Jun 26, 2023
7c5a350
[#4] Add test case for protocol mediator, run yarn fmt:ts
akshay-ap Jun 26, 2023
97fea95
[#4] Add test delegate contract, add test case for root access action
akshay-ap Jun 26, 2023
eec4486
[#4] Add test case: Non-enabled module should not be able to execute …
akshay-ap Jun 26, 2023
4e0a1aa
[#4] Use execTransactionFromModuleReturnData
akshay-ap Jun 26, 2023
5322a76
[#4] Add test case for failed root access action execution
akshay-ap Jun 26, 2023
514d964
[#4] Additional tests for 100% branch coverage for SafeProtocolMediat…
akshay-ap Jun 26, 2023
9f6abad
[#3] Add tests for coverage
akshay-ap Jun 26, 2023
51bde36
[#4] Fix lint issues
akshay-ap Jun 26, 2023
76b6c9d
[#4] Do not break loop if action execution fails
akshay-ap Jun 26, 2023
0364827
[#4] Add comment in SafeProtocolMediator.sol
akshay-ap Jun 26, 2023
0fc1f76
[#4] Revert on failed execution of action(s)
akshay-ap Jun 27, 2023
19302a0
[#4] Make mediator non-ownable as it is not neededas of now
akshay-ap Jun 27, 2023
8f06a1d
[#4] Update natspec doc, comment in mediator contract
akshay-ap Jun 27, 2023
e87d021
[#4] Combine logic for root access checks in executeRootAccess
akshay-ap Jun 27, 2023
a7fb792
[#4] Remove use of bignumber.js
akshay-ap Jun 27, 2023
d8b4c4c
[#4] Remove setModule from ISafe interface
akshay-ap Jun 27, 2023
ab6255a
[#4] Allow root enabled module to execute non-root actions
akshay-ap Jun 27, 2023
153f720
[#4] Disallow enabling a module twice
akshay-ap Jun 27, 2023
dbc32f7
[#4] Cache requiresRootAccess flag in enableModule
akshay-ap Jun 27, 2023
864b8a1
[#4] Fix typo
akshay-ap Jun 27, 2023
355ee7c
[#4] WIP: Get list of enabled modules paginated
akshay-ap Jun 27, 2023
a24e9b6
[#4] Add tests for enable module, disable module, minor changes in Sa…
akshay-ap Jun 28, 2023
b6ab3a0
[#4] Emit single event on executing actions
akshay-ap Jun 28, 2023
acdab1f
[#4] Add function modifier noZeroOrSentinelModule(address)
akshay-ap Jun 28, 2023
516df80
[#4] Use named parameters in mapping
akshay-ap Jun 28, 2023
5e0d550
Revert "[#4] Use named parameters in mapping"
akshay-ap Jun 28, 2023
ca9727b
Update contracts/interfaces/Mediator.sol
akshay-ap Jun 28, 2023
38c5c77
Update contracts/interfaces/Mediator.sol
akshay-ap Jun 28, 2023
de59754
Update contracts/interfaces/Mediator.sol
akshay-ap Jun 28, 2023
a413ea6
Update contracts/interfaces/Mediator.sol
akshay-ap Jun 28, 2023
9d4efc8
[#4] Remove empty DataTypes.ts
akshay-ap Jun 29, 2023
4bf35e1
Merge branch 'feature-4-module-mediator' of github.com:5afe/safe-prot…
akshay-ap Jun 29, 2023
c5ff7e9
[#4] Remove TODOs
akshay-ap Jun 29, 2023
eb32632
[#4] Rename test fallback receiver contracts
akshay-ap Jun 29, 2023
cc21da7
[#4] Remove 'enabled' flag from ModuleAccessInfo
akshay-ap Jun 29, 2023
941f844
[#4] Rename variable enabledComponents to enabledModules
akshay-ap Jun 29, 2023
65a45ea
[#4, #16] Remove todo related to checking interface id when enabling …
akshay-ap Jun 29, 2023
dcf91d7
Update contracts/SafeProtocolMediator.sol
akshay-ap Jun 30, 2023
76e6833
[#4] Remove unnecessary conversion to address, update comment
akshay-ap Jun 30, 2023
69c298c
Merge branch 'feature-4-module-mediator' of github.com:5afe/safe-prot…
akshay-ap Jun 30, 2023
6b4efde
[#4] Create variable for addresses used more than once in tests
akshay-ap Jun 30, 2023
270a02d
[#17] Add support for typescript file in lint
akshay-ap Jun 30, 2023
269da91
[#17] Lint fixes
akshay-ap Jun 30, 2023
69613fc
[#4] Create constant.ts file, add new line in a test
akshay-ap Jun 30, 2023
fce3346
[#17] Add new line at end of file in .eslintrc.js
akshay-ap Jun 30, 2023
8935860
Merge pull request #18 from 5afe/feature-17-setup-lint-for-typescript
akshay-ap Jun 30, 2023
a525b1a
[#4] Fix lint issue
akshay-ap Jun 30, 2023
9578e58
[#4] Index event params: Safe address and module
akshay-ap Jun 30, 2023
230ca19
[#19] Generate typings for solidity contracts
akshay-ap Jun 30, 2023
2412375
Merge pull request #20 from 5afe/feature-19-generate-typings
akshay-ap Jun 30, 2023
ba38ad0
[#4] Add flag for gas reporting
akshay-ap Jul 2, 2023
c9346bb
[#4] Set signers in fixture
akshay-ap Jul 2, 2023
040b4ad
[#4] Set signers in before function rather than in fixture
akshay-ap Jul 2, 2023
93bb344
Merge branch 'feature-19-generate-typings' into feature-4-module-medi…
akshay-ap Jul 2, 2023
28ae92d
Merge branch 'feature-17-setup-lint-for-typescript' into feature-4-mo…
akshay-ap Jul 2, 2023
54d6117
[#4] Optimize gas usage for enableModule function
akshay-ap Jul 3, 2023
3a4a3e2
[#4] Optimize gas usage for disableModule function
akshay-ap Jul 3, 2023
0b78794
[#1 #4] Add yarn fmt command
akshay-ap Jul 3, 2023
8f55555
[#4] Create builder.ts, dataTypes.ts, and use builder functions to cr…
akshay-ap Jul 3, 2023
ccf7c6e
[#4 #13] Update natspec docstring in ISafeProtocolMediator interface
akshay-ap Jul 3, 2023
b9734c1
[#4] Update test descriptions
akshay-ap Jul 3, 2023
67855ba
[#4] Update notice for executeTransaction
akshay-ap Jul 3, 2023
e030e3c
[#4] Cache array size to save gas usage
akshay-ap Jul 3, 2023
926191d
[#4] Optimize gas usage by removing conversions
akshay-ap Jul 3, 2023
c389ea8
[#4] Use calldata instead of memory to optimize gas usage
akshay-ap Jul 3, 2023
7172d5d
[#4] Fix contract name to TestFallbackReceiver in .solcover.js
akshay-ap Jul 4, 2023
6a0c4ba
Temp: User local variable safeAddress
akshay-ap Jul 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .solcover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
skipFiles: ['test/TestExecutor.sol', 'test/TestModule.sol', 'test/TestDelegateCallReceiver.sol']
};
2 changes: 1 addition & 1 deletion contracts/DataTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.18;

struct SafeProtocolAction {
address to;
address payable to;
uint256 value;
bytes data;
}
Expand Down
241 changes: 241 additions & 0 deletions contracts/SafeProtocolMediator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.18;
import {ISafeProtocolMediator} from "./interfaces/Mediator.sol";
import {ISafeProtocolModule} from "./interfaces/Components.sol";

import {ISafe} from "./interfaces/Accounts.sol";
import {SafeProtocolAction, SafeTransaction, SafeRootAccess} from "./DataTypes.sol";

/**
* @title SafeProtocolMediator contract allows Safe users to set module through a Mediator rather than directly enabling a module on Safe.
* Users have to first enable SafeProtocolMediator as a module on a Safe and then enable other modules through the mediator.
*/
contract SafeProtocolMediator is ISafeProtocolMediator {
address internal constant SENTINEL_MODULES = address(0x1);

/**
* @notice Mapping of a mapping what stores information about modules that are enabled per Safe.
* address (Safe address) => address (component address) => EnabledMoudleInfo
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
*/
mapping(address => mapping(address => ModuleAccessInfo)) public enabledModules;
struct ModuleAccessInfo {
bool rootAddressGranted;
address nextModulePointer;
}

// Events
event ActionsExecuted(address safe, bytes32 metaHash, uint256 nonce);
event RootAccessActionExecuted(address safe, bytes32 metaHash);
event ModuleEnabled(address safe, address module, bool allowRootAccess);
event ModuleDisabled(address safe, address module);
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved

// Errors
error ModuleRequiresRootAccess(address sender);
error MoudleNotEnabled(address module);
error ModuleEnabledOnlyForRootAccess(address module);
error ModuleAccessMismatch(address module, bool requiresRootAccess, bool providedValue);
error ActionExecutionFailed(address safe, bytes32 metaHash, uint256 index);
error RootAccessActionExecutionFailed(address safe, bytes32 metaHash);
error ModuleAlreadyEnabled(address safe, address module);
error InvalidModuleAddress(address module);
error InvalidPrevModuleAddress(address module);
error ZeroPageSizeNotAllowed();

modifier onlyEnabledModule(ISafe safe) {
if (enabledModules[address(safe)][msg.sender].nextModulePointer == address(0)) {
revert MoudleNotEnabled(msg.sender);
}
_;
}

modifier noZeroOrSentinelModule(address module) {
if (module == address(0) || module == SENTINEL_MODULES) {
revert InvalidModuleAddress(module);
}
_;
}

/**
* @notice This function executes a delegate call on a safe if the module is enabled and
* root access it granted.
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
* @param safe A Safe instance
* @param transaction A struct of type SafeTransaction containing information of about the action(s) to be executed.
* Users can add logic to validate metahash through a transaction guard.
* @return data bytes types containing the result of the executed action.
*/
function executeTransaction(
ISafe safe,
SafeTransaction calldata transaction
) external override onlyEnabledModule(safe) returns (bytes[] memory data) {
data = new bytes[](transaction.actions.length);
for (uint256 i = 0; i < transaction.actions.length; ++i) {
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
SafeProtocolAction memory safeProtocolAction = transaction.actions[i];
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
(bool isActionSuccessful, bytes memory resultData) = safe.execTransactionFromModuleReturnData(
safeProtocolAction.to,
safeProtocolAction.value,
safeProtocolAction.data,
0
);

// Need to revisit the approach below. If some actions fail, the transaction stiil succeeds.
// With current approach, even if one action fails, `data` will be empty bytes even for successful
// actions.
if (!isActionSuccessful) {
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
revert ActionExecutionFailed(address(safe), transaction.metaHash, i);
mmv08 marked this conversation as resolved.
Show resolved Hide resolved
} else {
data[i] = resultData;
}
}

emit ActionsExecuted(address(safe), transaction.metaHash, transaction.nonce);
}

/**
* @notice This function executes a delegate call on a safe if the module is enabled and
* root access it granted.
* @param safe A Safe instance
* @param rootAccess A struct of type SafeRootAccess containing information of about the action to be executed.
* Users can add logic to validate metahash through a transaction guard.
* @return data bytes types containing the result of the executed action.
*/
function executeRootAccess(
ISafe safe,
SafeRootAccess calldata rootAccess
mmv08 marked this conversation as resolved.
Show resolved Hide resolved
) external override onlyEnabledModule(safe) returns (bytes memory data) {
SafeProtocolAction memory safeProtocolAction = rootAccess.action;
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved

if (!ISafeProtocolModule(msg.sender).requiresRootAccess() || !enabledModules[address(safe)][msg.sender].rootAddressGranted) {
revert ModuleRequiresRootAccess(msg.sender);
}

bool success;
(success, data) = safe.execTransactionFromModuleReturnData(
safeProtocolAction.to,
safeProtocolAction.value,
safeProtocolAction.data,
1
);
if (success) {
emit RootAccessActionExecuted(address(safe), rootAccess.metaHash);
} else {
revert RootAccessActionExecutionFailed(address(safe), rootAccess.metaHash);
}
}

/**
* @notice Called by a Safe to enable a module on a Safe. To be called by a safe.
* @param module ISafeProtocolModule A module that has to be enabled
* @param allowRootAccess Bool indicating whether root access to be allowed.
*/
function enableModule(address module, bool allowRootAccess) external noZeroOrSentinelModule(module) {
if (enabledModules[msg.sender][module].nextModulePointer != address(0)) {
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
revert ModuleAlreadyEnabled(msg.sender, module);
}

bool requiresRootAccess = ISafeProtocolModule(module).requiresRootAccess();
if (allowRootAccess != requiresRootAccess) {
revert ModuleAccessMismatch(module, requiresRootAccess, allowRootAccess);
}

if (enabledModules[msg.sender][SENTINEL_MODULES].nextModulePointer == address(0)) {
// The circular linked list has not been initialised yet for msg.sender. So, do it now.
enabledModules[msg.sender][SENTINEL_MODULES] = ModuleAccessInfo(false, SENTINEL_MODULES);
}

enabledModules[msg.sender][address(module)] = ModuleAccessInfo(
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
allowRootAccess,
enabledModules[msg.sender][SENTINEL_MODULES].nextModulePointer
);
enabledModules[msg.sender][SENTINEL_MODULES] = ModuleAccessInfo(false, address(module));

emit ModuleEnabled(msg.sender, address(module), allowRootAccess);
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* @notice Disable a module. This function should be called by Safe.
* @param module Module to be disabled
*/
function disableModule(address prevModule, address module) external noZeroOrSentinelModule(module) {
if (enabledModules[msg.sender][prevModule].nextModulePointer != module) {
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
revert InvalidPrevModuleAddress(prevModule);
}

enabledModules[msg.sender][prevModule] = enabledModules[msg.sender][module];

enabledModules[msg.sender][module] = ModuleAccessInfo(false, address(0));
emit ModuleDisabled(msg.sender, module);
}

/**
* @notice A view only function to get information about safe and a module
* @param safe Address of a safe
* @param module Address of a module
*/
function getModuleInfo(address safe, address module) external view returns (ModuleAccessInfo memory enabled) {
return enabledModules[safe][module];
}

/**
* @notice Returns if an module is enabled
* @return True if the module is enabled
*/
function isModuleEnabled(address safe, address module) public view returns (bool) {
return SENTINEL_MODULES != module && enabledModules[safe][module].nextModulePointer != address(0);
}

/**
* @notice Returns an array of modules enabled for a Safe address.
* If all entries fit into a single page, the next pointer will be 0x1.
* If another page is present, next will be the last element of the returned array.
* @param start Start of the page. Has to be a module or start pointer (0x1 address)
* @param pageSize Maximum number of modules that should be returned. Has to be > 0
* @return array Array of modules.
* @return next Start of the next page.
*/
function getModulesPaginated(
address start,
uint256 pageSize,
address safe
) external view returns (address[] memory array, address next) {
if (pageSize == 0) {
revert ZeroPageSizeNotAllowed();
}

if (!(start == SENTINEL_MODULES || isModuleEnabled(safe, start))) {
revert InvalidModuleAddress(start);
}
// Init array with max page size
array = new address[](pageSize);

// Populate return array
uint256 moduleCount = 0;
next = enabledModules[safe][start].nextModulePointer;
while (next != address(0) && next != SENTINEL_MODULES && moduleCount < pageSize) {
array[moduleCount] = next;
next = enabledModules[safe][next].nextModulePointer;
moduleCount++;
}

// This check is required because the enabled module list might not be initialised yet. e.g. no enabled modules for a safe ever before
if (moduleCount == 0) {
next = SENTINEL_MODULES;
}

/**
Because of the argument validation, we can assume that the loop will always iterate over the valid module list values
and the `next` variable will either be an enabled module or a sentinel address (signalling the end).

If we haven't reached the end inside the loop, we need to set the next pointer to the last element of the modules array
because the `next` variable (which is a module by itself) acting as a pointer to the start of the next page is neither
included to the current page, nor will it be included in the next one if you pass it as a start.
*/
if (next != SENTINEL_MODULES && moduleCount != 0) {
next = array[moduleCount - 1];
}
// Set correct size of returned array
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(array, moduleCount)
}
}
}
4 changes: 2 additions & 2 deletions contracts/SafeProtocolRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.18;
import "./interfaces/ISafeProtocolRegistry.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import {ISafeProtocolRegistry} from "./interfaces/ISafeProtocolRegistry.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";

contract SafeProtocolRegistry is ISafeProtocolRegistry, Ownable2Step {
/**
Expand Down
12 changes: 12 additions & 0 deletions contracts/interfaces/Accounts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,17 @@ pragma solidity ^0.8.18;
* @title ISafe Declares the functions that are called on a Safe by Safe protocol.
*/
interface ISafe {
function execTransactionFromModule(
address payable to,
uint256 value,
bytes calldata data,
uint8 operation
) external returns (bool success);

function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes memory data,
uint8 operation
) external returns (bool success, bytes memory returnData);
}
4 changes: 2 additions & 2 deletions contracts/interfaces/Components.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.18;
import "./Accounts.sol";
import "../DataTypes.sol";
import {ISafe} from "./Accounts.sol";
import {SafeTransaction, SafeRootAccess} from "../DataTypes.sol";

/**
* @title ISafeProtocolStaticFallbackMethod - An interface that a Safe fallbackhandler should implement
Expand Down
30 changes: 30 additions & 0 deletions contracts/interfaces/Mediator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.18;
import {ISafe} from "./Accounts.sol";
import {SafeRootAccess, SafeTransaction} from "../DataTypes.sol";

/**
* @title ISafeProtocolMediator interface a Mediator should implement
* @notice A mediator checks the status of the component through the registry and allows only
* listed and non-flagged components to execute transactions. A Safe account should
* add a mediator as a module.
*/
interface ISafeProtocolMediator {
/**
* @notice TODO
akshay-ap marked this conversation as resolved.
Show resolved Hide resolved
* @param safe Instance of a Safe account
* @param transaction SafeTransaction instance containing payload information about the transaction
* @return data Array of bytes types returned upon the successful execution of all the actions. The size of the array will be the same as the size of the actions
* in case of succcessful execution. Empty if the call failed.
*/
function executeTransaction(ISafe safe, SafeTransaction calldata transaction) external returns (bytes[] memory data);

/**
* @notice TODO
* @param safe Instance of a Safe account
* @param rootAccess SafeTransaction instance containing payload information about the transaction
* @return data Arbitrary length bytes data returned upon the successful execution. The size of the array will be the same as the size of the actions
* in case of succcessful execution. Empty if the call failed.
*/
function executeRootAccess(ISafe safe, SafeRootAccess calldata rootAccess) external returns (bytes memory data);
}
63 changes: 63 additions & 0 deletions contracts/test/TestExecutor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.18;
import {ISafe} from "../interfaces/Accounts.sol";

contract TestExecutor is ISafe {
address public module;
address[] public owners;

function setModule(address _module) external {
module = _module;
}

function exec(address payable to, uint256 value, bytes calldata data) external {
bool success;
bytes memory response;
(success, response) = to.call{value: value}(data);
if (!success) {
// solhint-disable-next-line no-inline-assembly
assembly {
revert(add(response, 0x20), mload(response))
}
}
}

function execTransactionFromModule(
address payable to,
uint256 value,
bytes calldata data,
uint8 operation
) external returns (bool success) {
require(msg.sender == module, "Not authorized");
if (operation == 1) (success, ) = to.delegatecall(data);
else (success, ) = to.call{value: value}(data);
}

function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes memory data,
uint8 operation
) public returns (bool success, bytes memory returnData) {
require(msg.sender == module, "Not authorized");
if (operation == 1) (success, ) = to.delegatecall(data);
else (success, ) = to.call{value: value}(data); // solhint-disable-next-line no-inline-assembly

// solhint-disable-next-line no-inline-assembly
assembly {
// Load free memory location
let ptr := mload(0x40)
// We allocate memory for the return data by setting the free memory location to
// current free memory location + data size + 32 bytes for data size value
mstore(0x40, add(ptr, add(returndatasize(), 0x20)))
// Store the size
mstore(ptr, returndatasize())
// Store the data
returndatacopy(add(ptr, 0x20), 0, returndatasize())
// Point the return data to the correct memory location
returnData := ptr
}
}

receive() external payable {}
}
Loading