Skip to content
This repository was archived by the owner on Aug 26, 2024. It is now read-only.

Commit 388c62f

Browse files
authored
Merge pull request #75 from ionicprotocol/feat/liquidate-borrow-permissioning
modifier for blocking unwanted liquidations on ctoken
2 parents 7969359 + 846503f commit 388c62f

16 files changed

+5120
-8147
lines changed

chainDeploy/helpers/logging.ts

Lines changed: 79 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,94 @@
1+
import { encodeFunctionData } from "viem"; // Adjust the import path according to your project structure
12
import { promises as fs } from "fs";
23

4+
interface PrepareAndLogTransactionParams {
5+
contractInstance: any; // Replace `any` with the correct contract type if available
6+
functionName: string;
7+
args: any[];
8+
description: string;
9+
inputs: {
10+
internalType: string;
11+
name: string;
12+
type: string;
13+
}[];
14+
}
15+
316
export const logTransaction = (description: string, data: string) => {
417
console.log(`Transaction: ${description}`);
518
console.log(`Data: ${data}`);
619
};
720

821
const transactions: any[] = [];
922

10-
export const addTransaction = (tx: any) => {
23+
export const addTransaction = async (tx: any) => {
1124
transactions.push(tx);
25+
await writeSingleTransactionToFile(tx);
26+
};
27+
28+
const writeSingleTransactionToFile = async (tx: any) => {
29+
const filePath = "./transactions.json";
30+
try {
31+
let batch;
32+
try {
33+
const fileContent = await fs.readFile(filePath, "utf8");
34+
batch = JSON.parse(fileContent);
35+
} catch (error) {
36+
if (error.code === "ENOENT" || error.message === "Unexpected end of JSON input") {
37+
batch = {
38+
version: "1.0",
39+
chainId: "34443",
40+
createdAt: Math.floor(Date.now() / 1000),
41+
meta: {
42+
name: "Transactions Batch",
43+
description: "",
44+
txBuilderVersion: "1.16.5",
45+
createdFromSafeAddress: "0x8Fba84867Ba458E7c6E2c024D2DE3d0b5C3ea1C2",
46+
createdFromOwnerAddress: "",
47+
checksum: "0x"
48+
},
49+
transactions: []
50+
};
51+
} else {
52+
throw error;
53+
}
54+
}
55+
56+
batch.transactions.push(tx);
57+
58+
await fs.writeFile(filePath, JSON.stringify(batch, null, 2));
59+
console.log(`Transaction added and written to ${filePath}`);
60+
} catch (error) {
61+
console.error(`Failed to write transaction to ${filePath}`, error);
62+
}
1263
};
1364

14-
export const writeTransactionsToFile = async () => {
15-
const batch = {
16-
version: "1.0",
17-
chainId: "34443",
18-
createdAt: Math.floor(Date.now() / 1000),
19-
meta: {
20-
name: "Transactions Batch",
21-
description: "",
22-
txBuilderVersion: "1.16.5",
23-
createdFromSafeAddress: "0x8Fba84867Ba458E7c6E2c024D2DE3d0b5C3ea1C2",
24-
createdFromOwnerAddress: "",
25-
checksum: "0x"
65+
export const prepareAndLogTransaction = async ({
66+
contractInstance,
67+
functionName,
68+
args,
69+
description,
70+
inputs
71+
}: PrepareAndLogTransactionParams) => {
72+
const data = encodeFunctionData({
73+
abi: contractInstance.abi,
74+
functionName,
75+
args
76+
});
77+
78+
await addTransaction({
79+
to: contractInstance.address,
80+
value: "0",
81+
data,
82+
contractMethod: {
83+
inputs,
84+
name: functionName,
85+
payable: false
2686
},
27-
transactions
28-
};
87+
contractInputsValues: args.reduce((acc: any, arg: any, index: number) => {
88+
acc[inputs[index].name] = arg;
89+
return acc;
90+
}, {})
91+
});
2992

30-
const filePath = "./transactions.json";
31-
await fs.writeFile(filePath, JSON.stringify(batch, null, 2));
32-
console.log(`Transactions written to ${filePath}`);
93+
logTransaction(description, data);
3394
};

contracts/compound/CToken.sol

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { InterestRateModel } from "./InterestRateModel.sol";
1010
import { ComptrollerV3Storage } from "./ComptrollerStorage.sol";
1111
import { IFeeDistributor } from "./IFeeDistributor.sol";
1212
import { DiamondExtension, LibDiamond } from "../ionic/DiamondExtension.sol";
13+
import { PoolLens } from "../PoolLens.sol";
14+
import { IonicUniV3Liquidator } from "../IonicUniV3Liquidator.sol";
1315

1416
/**
1517
* @title Compound's CErc20 Contract
@@ -26,6 +28,18 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
2628
_;
2729
}
2830

31+
modifier isMinHFThresholdExceeded(address borrower) {
32+
PoolLens lens = PoolLens(ap.getAddress("PoolLens"));
33+
IonicUniV3Liquidator liquidator = IonicUniV3Liquidator(payable(ap.getAddress("IonicUniV3Liquidator")));
34+
35+
if (lens.getHealthFactor(borrower, comptroller) > liquidator.healthFactorThreshold()) {
36+
require(msg.sender == address(liquidator), "Health factor not low enough for non-permissioned liquidations");
37+
_;
38+
} else {
39+
_;
40+
}
41+
}
42+
2943
function _getExtensionFunctions() public pure virtual override returns (bytes4[] memory) {
3044
uint8 fnsCount = 13;
3145
bytes4[] memory functionSelectors = new bytes4[](fnsCount);
@@ -122,7 +136,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
122136
address borrower,
123137
uint256 repayAmount,
124138
address cTokenCollateral
125-
) external override isAuthorized returns (uint256) {
139+
) external override isAuthorized isMinHFThresholdExceeded(borrower) returns (uint256) {
126140
(uint256 err, ) = liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral);
127141
return err;
128142
}

contracts/compound/CTokenFirstExtension.sol

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import { Multicall } from "../utils/Multicall.sol";
1313

1414
import { IERC20, SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
1515

16+
import { AddressesProvider } from "../ionic/AddressesProvider.sol";
17+
1618
contract CTokenFirstExtension is
1719
CErc20FirstExtensionBase,
1820
TokenErrorReporter,
@@ -29,7 +31,7 @@ contract CTokenFirstExtension is
2931
}
3032

3133
function _getExtensionFunctions() external pure virtual override returns (bytes4[] memory) {
32-
uint8 fnsCount = 24;
34+
uint8 fnsCount = 25;
3335
bytes4[] memory functionSelectors = new bytes4[](fnsCount);
3436
functionSelectors[--fnsCount] = this.transfer.selector;
3537
functionSelectors[--fnsCount] = this.transferFrom.selector;
@@ -39,6 +41,7 @@ contract CTokenFirstExtension is
3941
functionSelectors[--fnsCount] = this._setAdminFee.selector;
4042
functionSelectors[--fnsCount] = this._setInterestRateModel.selector;
4143
functionSelectors[--fnsCount] = this._setNameAndSymbol.selector;
44+
functionSelectors[--fnsCount] = this._setAddressesProvider.selector;
4245
functionSelectors[--fnsCount] = this._setReserveFactor.selector;
4346
functionSelectors[--fnsCount] = this.supplyRatePerBlock.selector;
4447
functionSelectors[--fnsCount] = this.borrowRatePerBlock.selector;
@@ -219,6 +222,13 @@ contract CTokenFirstExtension is
219222
symbol = _symbol;
220223
}
221224

225+
function _setAddressesProvider(address _ap) external {
226+
// Check caller is admin
227+
require(hasAdminRights(), "!admin");
228+
229+
ap = AddressesProvider(_ap);
230+
}
231+
222232
/**
223233
* @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
224234
* @dev Admin function to accrue interest and set a new reserve factor

contracts/compound/CTokenInterfaces.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pragma solidity >=0.8.0;
44
import { IonicComptroller } from "./ComptrollerInterface.sol";
55
import { InterestRateModel } from "./InterestRateModel.sol";
66
import { ComptrollerV3Storage } from "./ComptrollerStorage.sol";
7+
import { AddressesProvider } from "../ionic/AddressesProvider.sol";
78

89
abstract contract CTokenAdminStorage {
910
/*
@@ -147,6 +148,11 @@ abstract contract CErc20Storage is CTokenAdminStorage {
147148
* @notice Underlying asset for this CToken
148149
*/
149150
address public underlying;
151+
152+
/**
153+
* @notice Addresses Provider
154+
*/
155+
AddressesProvider public ap;
150156
}
151157

152158
abstract contract CTokenBaseEvents {

0 commit comments

Comments
 (0)