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

Revert BatchLiquidator #1817

Closed
wants to merge 2 commits into from
Closed
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
138 changes: 56 additions & 82 deletions packages/ethereum-contracts/contracts/utils/BatchLiquidator.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;

import {
ISuperfluid, ISuperAgreement, ISuperToken, ISuperfluidPool,
IConstantFlowAgreementV1, IGeneralDistributionAgreementV1
} from "../interfaces/superfluid/ISuperfluid.sol";
import { ISuperfluid, ISuperAgreement, ISuperToken } from "../interfaces/superfluid/ISuperfluid.sol";
import { IConstantFlowAgreementV1 } from "../interfaces/agreements/IConstantFlowAgreementV1.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
Expand All @@ -15,47 +13,52 @@ import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
*/

contract BatchLiquidator {
enum FlowType {
ConstantFlowAgreement,
GeneralDistributionAgreement
}

struct FlowLiquidationData {
FlowType agreementOperation;
address sender;
address receiver;
}
error ARRAY_SIZES_DIFFERENT();

address public immutable host;
address public immutable cfa;
address public immutable gda;

constructor(address host_) {
constructor(address host_, address cfa_) {
host = host_;
cfa = address(
ISuperfluid(host).getAgreementClass(keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1"))
);
gda = address(
ISuperfluid(host).getAgreementClass(
keccak256("org.superfluid-finance.agreements.GeneralDistributionAgreement.v1")
)
);
cfa = cfa_;
}

/**
* @dev Delete flows in batch
* @param superToken - The super token the flows belong to.
* @param data - The array of flow data to be deleted.
* @param senders - List of senders.
* @param receivers - Corresponding list of receivers.
*/
function deleteFlows(address superToken, FlowLiquidationData[] memory data) external {
for (uint256 i; i < data.length;) {
function deleteFlows(
address superToken,
address[] calldata senders, address[] calldata receivers
) external {
uint256 length = senders.length;
if(length != receivers.length) revert ARRAY_SIZES_DIFFERENT();
for (uint256 i; i < length;) {
// We tolerate any errors occured during liquidations.
// It could be due to flow had been liquidated by others.
_deleteFlow(superToken, data[i]);

unchecked {
i++;
}
// solhint-disable-next-line avoid-low-level-calls
address(host).call(
abi.encodeCall(
ISuperfluid(host).callAgreement,
(
ISuperAgreement(cfa),
abi.encodeCall(
IConstantFlowAgreementV1(cfa).deleteFlow,
(
ISuperToken(superToken),
senders[i],
receivers[i],
new bytes(0)
)
),
new bytes(0)
)
)
);
unchecked { i++; }
}

// If the liquidation(s) resulted in any super token
Expand All @@ -64,22 +67,32 @@ contract BatchLiquidator {
{
uint256 balance = ERC20(superToken).balanceOf(address(this));
if (balance > 0) {
// don't fail for non-transferrable tokens
try ERC20(superToken).transferFrom(address(this), msg.sender, balance)
// solhint-disable-next-line no-empty-blocks
{} catch {}
ERC20(superToken).transferFrom(address(this), msg.sender, balance);
}
}
}

/**
* @dev Delete a single flow
* @param superToken - The super token the flow belongs to.
* @param data - The flow data to be deleted.
*/
function deleteFlow(address superToken, FlowLiquidationData memory data) external {
// single flow delete with check for success
function deleteFlow(address superToken, address sender, address receiver) external {
/* solhint-disable */
(bool success, bytes memory returndata) = _deleteFlow(superToken, data);
(bool success, bytes memory returndata) = address(host).call(
abi.encodeCall(
ISuperfluid(host).callAgreement,
(
ISuperAgreement(cfa),
abi.encodeCall(
IConstantFlowAgreementV1(cfa).deleteFlow,
(
ISuperToken(superToken),
sender,
receiver,
new bytes(0)
)
),
new bytes(0)
)
)
);
if (!success) {
if (returndata.length == 0) revert();
// solhint-disable
Expand All @@ -94,47 +107,8 @@ contract BatchLiquidator {
{
uint256 balance = ERC20(superToken).balanceOf(address(this));
if (balance > 0) {
try ERC20(superToken).transferFrom(address(this), msg.sender, balance)
// solhint-disable-next-line no-empty-blocks
{} catch {}
ERC20(superToken).transferFrom(address(this), msg.sender, balance);
}
}
}

function _deleteFlow(address superToken, FlowLiquidationData memory data)
internal
returns (bool success, bytes memory returndata)
{
if (data.agreementOperation == FlowType.ConstantFlowAgreement) {
// solhint-disable-next-line avoid-low-level-calls
(success, returndata) = address(host).call(
abi.encodeCall(
ISuperfluid(host).callAgreement,
(
ISuperAgreement(cfa),
abi.encodeCall(
IConstantFlowAgreementV1(cfa).deleteFlow,
(ISuperToken(superToken), data.sender, data.receiver, new bytes(0))
),
new bytes(0)
)
)
);
} else {
// solhint-disable-next-line avoid-low-level-calls
(success, returndata) = address(host).call(
abi.encodeCall(
ISuperfluid(host).callAgreement,
(
ISuperAgreement(gda),
abi.encodeCall(
IGeneralDistributionAgreementV1(gda).distributeFlow,
(ISuperToken(superToken), data.sender, ISuperfluidPool(data.receiver), 0, new bytes(0))
),
new bytes(0)
)
)
);
}
}
}
Loading
Loading