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

feat: add MutliCall #867

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 23 additions & 0 deletions contracts/interfaces/IPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,21 @@ interface IPool {
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/

enum MultiCallAction {
Supply,
Borrow,
Repay,
Withdraw,
SetUserUseReserveAsCollateral,
SwapBorrowRateMode,
RebalanceStableBorrowRate,
SupplyWithPermit,
RepayWithPermit,
RepayWithATokens,
LiquidationCall
}

function mintUnbacked(
address asset,
uint256 amount,
Expand Down Expand Up @@ -464,6 +479,14 @@ interface IPool {
uint16 referralCode
) external;

/**
* @notice Allows to batch call any user relevant functions in a single transaction,
* any revert in any of the actions being executed, will result in a revert of the batch
* @param actions includes the set of MultiCallAction that a user is able to execute
* @param params Array of encoded MultiCallAction parameters
*/
function multiCall(bytes calldata actions, bytes[] calldata params) external;

/**
* @notice Returns the user account data across all the reserves
* @param user The address of the user
Expand Down
45 changes: 45 additions & 0 deletions contracts/protocol/libraries/types/Calldata.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
pragma solidity ^0.8.0;

library Calldata {
function getAddress(bytes calldata self) internal pure returns (address output) {
assembly {
output := calldataload(self.offset)
}
}

function getAddress(bytes calldata self, uint8 index) internal pure returns (address output) {
assembly {
output := calldataload(add(self.offset, mul(index, 0x20)))
}
}

function getUint256(bytes calldata self, uint8 index) internal pure returns (uint output) {
assembly {
output := calldataload(add(self.offset, mul(index, 0x20)))
}
}

function getUint16(bytes calldata self, uint8 index) internal pure returns (uint16 output) {
assembly {
output := calldataload(add(self.offset, mul(index, 0x20)))
}
}

function getUint8(bytes calldata self, uint8 index) internal pure returns (uint8 output) {
assembly {
output := calldataload(add(self.offset, mul(index, 0x20)))
}
}

function getBool(bytes calldata self, uint8 index) internal pure returns (bool output) {
assembly {
output := calldataload(add(self.offset, mul(index, 0x20)))
}
}

function getBytes32(bytes calldata self, uint8 index) internal pure returns (bytes32 output) {
assembly {
output := calldataload(add(self.offset, mul(index, 0x20)))
}
}
}
68 changes: 68 additions & 0 deletions contracts/protocol/pool/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {FlashLoanLogic} from '../libraries/logic/FlashLoanLogic.sol';
import {BorrowLogic} from '../libraries/logic/BorrowLogic.sol';
import {LiquidationLogic} from '../libraries/logic/LiquidationLogic.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol';
import {Calldata} from '../libraries/types/Calldata.sol';
import {BridgeLogic} from '../libraries/logic/BridgeLogic.sol';
import {IERC20WithPermit} from '../../interfaces/IERC20WithPermit.sol';
import {IPoolAddressesProvider} from '../../interfaces/IPoolAddressesProvider.sol';
Expand All @@ -38,6 +39,7 @@ import {PoolStorage} from './PoolStorage.sol';
*/
contract Pool is VersionedInitializable, PoolStorage, IPool {
using ReserveLogic for DataTypes.ReserveData;
using Calldata for bytes;

uint256 public constant POOL_REVISION = 0x1;
IPoolAddressesProvider public immutable ADDRESSES_PROVIDER;
Expand Down Expand Up @@ -440,6 +442,72 @@ contract Pool is VersionedInitializable, PoolStorage, IPool {
FlashLoanLogic.executeFlashLoanSimple(_reserves[asset], flashParams);
}

/// @inheritdoc IPool
function multiCall(bytes calldata actions, bytes[] calldata params) public override {
uint len = actions.length;
require(len == params.length, Errors.INCONSISTENT_PARAMS_LENGTH);
for (uint i; i < len; ) {
MultiCallAction action = MultiCallAction(uint8(actions[i]));
bytes calldata param = params[i];
if (action == MultiCallAction.Supply) {
supply(param.getAddress(), param.getUint256(1), param.getAddress(2), param.getUint16(3));
} else if (action == MultiCallAction.Borrow) {
borrow(
param.getAddress(),
param.getUint256(1),
param.getUint256(2),
param.getUint16(3),
param.getAddress(4)
);
} else if (action == MultiCallAction.Repay) {
repay(param.getAddress(), param.getUint256(1), param.getUint256(2), param.getAddress(3));
} else if (action == MultiCallAction.Withdraw) {
withdraw(param.getAddress(), param.getUint256(1), param.getAddress(2));
} else if (action == MultiCallAction.SetUserUseReserveAsCollateral) {
setUserUseReserveAsCollateral(param.getAddress(), param.getBool(1));
} else if (action == MultiCallAction.SwapBorrowRateMode) {
swapBorrowRateMode(param.getAddress(), param.getUint256(1));
} else if (action == MultiCallAction.RebalanceStableBorrowRate) {
rebalanceStableBorrowRate(param.getAddress(), param.getAddress(1));
} else if (action == MultiCallAction.SupplyWithPermit) {
supplyWithPermit(
param.getAddress(),
param.getUint256(1),
param.getAddress(2),
param.getUint16(3),
param.getUint256(4),
param.getUint8(5),
param.getBytes32(6),
param.getBytes32(7)
);
} else if (action == MultiCallAction.RepayWithPermit) {
repayWithPermit(
param.getAddress(),
param.getUint256(1),
param.getUint256(2),
param.getAddress(3),
param.getUint256(4),
param.getUint8(5),
param.getBytes32(6),
param.getBytes32(7)
);
} else if (action == MultiCallAction.RepayWithATokens) {
repayWithATokens(param.getAddress(), param.getUint256(1), param.getUint256(2));
} else if (action == MultiCallAction.LiquidationCall) {
liquidationCall(
param.getAddress(),
param.getAddress(1),
param.getAddress(2),
param.getUint256(3),
param.getBool(4)
);
}
unchecked {
i++;
}
}
}

/// @inheritdoc IPool
function mintToTreasury(address[] calldata assets) external virtual override {
PoolLogic.executeMintToTreasury(_reserves, assets);
Expand Down