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

Otherdeed Flashclaim #379

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 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
7 changes: 7 additions & 0 deletions contracts/interfaces/IPoolPositionMover.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,11 @@ pragma solidity 0.8.10;
**/
interface IPoolPositionMover {
function movePositionFromBendDAO(uint256[] calldata loanIds) external;

function claimOtherExpandedAndSupply(
uint256[] calldata otherdeedIds,
uint256[] calldata kodaIds,
uint256[] calldata kodaOtherdeedIds,
bytes32[][] calldata merkleProofs
) external;
}
13 changes: 13 additions & 0 deletions contracts/interfaces/IVesselClaim.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

interface IVesselClaim {
function claimVesselsAndKodas(
uint256[] calldata otherdeedIds,
uint256[] calldata kodaIds,
uint256[] calldata kodaOtherdeedIds,
bytes32[][] calldata merkleProofs
) external;

function claimVessels(uint256[] calldata otherdeedIds) external;
}
48 changes: 48 additions & 0 deletions contracts/mocks/MockVessel.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

import {MintableERC721} from "./tokens/MintableERC721.sol";

contract MockVessel is MintableERC721 {

MintableERC721 immutable KODA;
MintableERC721 immutable OTHRE;
MintableERC721 immutable OTHR;

constructor(MintableERC721 otherdeed, MintableERC721 kodaAddress, MintableERC721 otherdeedExpAddress) MintableERC721("VESSEL", "VSL", "") {
OTHR = otherdeed;
KODA = kodaAddress;
OTHRE = otherdeedExpAddress;
}

function claimVesselsAndKodas(
uint256[] calldata otherdeedIds,
uint256[] calldata kodaIds,
uint256[] calldata kodaOtherdeedIds,
bytes32[][] calldata merkleProofs
)
external {

for (uint256 index = 0; index < otherdeedIds.length; index++) {
mintTokenId(msg.sender, otherdeedIds[index]);
OTHRE.mintTokenId(msg.sender, otherdeedIds[index]);

OTHR.transferFrom(msg.sender, 0x000000000000000000000000000000000000dEaD, otherdeedIds[index]);
}

for (uint256 index = 0; index < kodaIds.length; index++) {
KODA.mintTokenId(msg.sender, kodaIds[index]);
}
}


function claimVessels(uint256[] calldata otherdeedIds)
external {
for (uint256 index = 0; index < otherdeedIds.length; index++) {
mintTokenId(msg.sender, otherdeedIds[index]);
OTHRE.mintTokenId(msg.sender, otherdeedIds[index]);

OTHR.transferFrom(msg.sender, 0x000000000000000000000000000000000000dEaD, otherdeedIds[index]);
}
}
}
8 changes: 5 additions & 3 deletions contracts/mocks/tokens/Land.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1182,7 +1182,7 @@ contract Land is ERC721Enumerable, Ownable {
MAX_FUTURE_LANDS = amount.future;

betaNftIdCurrent = amount.alpha; //beta starts after alpha
mintIndexPublicSaleAndContributors = amount.alpha + amount.beta; //public sale starts after beta
mintIndexPublicSaleAndContributors = 0; //public sale starts after beta

RESERVED_CONTRIBUTORS_AMOUNT = 10000;

Expand Down Expand Up @@ -1214,7 +1214,8 @@ contract Land is ERC721Enumerable, Ownable {
totalSupply() + 1 <= collectionSize,
"exceed collectionSize"
);
_safeMint(_to, mintIndexPublicSaleAndContributors++);
_safeMint(_to, mintIndexPublicSaleAndContributors);
mintIndexPublicSaleAndContributors++;
}

function mint(uint256 count, address to) public virtual {
Expand All @@ -1223,8 +1224,9 @@ contract Land is ERC721Enumerable, Ownable {
"exceed collectionSize"
);
for (uint256 i = 0; i < count; i++) {
mintIndexPublicSaleAndContributors++;

_safeMint(to, mintIndexPublicSaleAndContributors);
mintIndexPublicSaleAndContributors++;
}
}

Expand Down
6 changes: 6 additions & 0 deletions contracts/mocks/tokens/MintableERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ contract MintableERC721 is Context, ERC721Enumerable {
}
}

function mintTokenId(address to, uint256 _tokenId) public virtual {
// We cannot just use balanceOf to create the new tokenId because tokens
// can be burned (destroyed), so we need a separate counter.
_mint(to, _tokenId);
}

function setBaseURI(string memory baseTokenURI) external {
_baseTokenURI = baseTokenURI;
}
Expand Down
132 changes: 132 additions & 0 deletions contracts/protocol/libraries/logic/PositionMoverLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
pragma solidity 0.8.10;

import {INToken} from "../../../interfaces/INToken.sol";
import {IVesselClaim} from "../../../interfaces/IVesselClaim.sol";
import {IPoolAddressesProvider} from "../../../interfaces/IPoolAddressesProvider.sol";
import {DataTypes} from "../types/DataTypes.sol";
import {IPToken} from "../../../interfaces/IPToken.sol";
import {IERC20} from "../../../dependencies/openzeppelin/contracts/IERC20.sol";
import {IERC721} from "../../../dependencies/openzeppelin/contracts/IERC721.sol";

import {Errors} from "../helpers/Errors.sol";
import {ValidationLogic} from "./ValidationLogic.sol";
import {SupplyLogic} from "./SupplyLogic.sol";
import {BorrowLogic} from "./BorrowLogic.sol";
import {ReserveLogic} from "./ReserveLogic.sol";
import {ReserveConfiguration} from "../configuration/ReserveConfiguration.sol";
import {UserConfiguration} from "../configuration/UserConfiguration.sol";
import {Address} from "../../../dependencies/openzeppelin/contracts/Address.sol";
import {ILendPoolLoan} from "../../../dependencies/benddao/contracts/interfaces/ILendPoolLoan.sol";
import {ILendPool} from "../../../dependencies/benddao/contracts/interfaces/ILendPool.sol";
Expand All @@ -25,6 +29,7 @@ import {BDaoDataTypes} from "../../../dependencies/benddao/contracts/libraries/t
library PositionMoverLogic {
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using ReserveLogic for DataTypes.ReserveData;
using UserConfiguration for DataTypes.UserConfigurationMap;

struct PositionMoverVars {
address weth;
Expand All @@ -35,6 +40,10 @@ library PositionMoverLogic {
}

event PositionMoved(address asset, uint256 tokenId, address user);
event ReserveUsedAsCollateralDisabled(
address indexed reserve,
address indexed user
);

function executeMovePositionFromBendDAO(
DataTypes.PoolStorage storage ps,
Expand Down Expand Up @@ -148,4 +157,127 @@ library PositionMoverLogic {
})
);
}

function executeClaimOtherdeedAndSupply(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
DataTypes.UserConfigurationMap storage userConfig,
DataTypes.OtherdeedClaimParams memory params
) external returns (uint256) {
DataTypes.ReserveData storage reserve = reservesData[params.otherdeed];
DataTypes.ReserveCache memory reserveCache = reserve.cache();

ValidationLogic.validateWithdrawERC721(
reservesData,
reserveCache,
params.otherdeed,
params.otherdeedIds
);

DataTypes.TimeLockParams memory timeLockParams;

(
uint64 oldCollateralizedBalance,
uint64 newCollateralizedBalance
) = INToken(reserveCache.xTokenAddress).burn(
msg.sender,
address(this),
params.otherdeedIds,
timeLockParams
);

bool isWithdrawCollateral = (newCollateralizedBalance <
oldCollateralizedBalance);

if (isWithdrawCollateral) {
if (newCollateralizedBalance == 0) {
userConfig.setUsingAsCollateral(reserve.id, false);
emit ReserveUsedAsCollateralDisabled(
params.otherdeed,
msg.sender
);
}
}

IERC721(params.otherdeed).setApprovalForAll(params.vessel, true);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we do this only once? I made it this way for security reason


if (params.kodaIds.length == 0) {
IVesselClaim(params.vessel).claimVessels(params.otherdeedIds);
} else {
IVesselClaim(params.vessel).claimVesselsAndKodas(
params.otherdeedIds,
params.kodaIds,
params.kodaOtherdeedIds,
params.merkleProofs
);
}

IERC721(params.otherdeed).setApprovalForAll(params.vessel, false);

SupplyLogic.executeSupplyERC721(
reservesData,
userConfig,
DataTypes.ExecuteSupplyERC721Params({
asset: params.otherdeedExpanded,
tokenData: _getTokenData(params.otherdeedIds),
GopherJ marked this conversation as resolved.
Show resolved Hide resolved
onBehalfOf: msg.sender,
payer: address(this),
referralCode: 0x0
})
);

SupplyLogic.executeSupplyERC721(
reservesData,
userConfig,
DataTypes.ExecuteSupplyERC721Params({
asset: params.vessel,
tokenData: _getTokenData(params.otherdeedIds),
onBehalfOf: msg.sender,
payer: address(this),
referralCode: 0x0
})
);

if (params.kodaIds.length != 0) {
SupplyLogic.executeSupplyERC721(
reservesData,
userConfig,
DataTypes.ExecuteSupplyERC721Params({
asset: params.koda,
tokenData: _getTokenData(params.kodaIds),
onBehalfOf: msg.sender,
payer: address(this),
referralCode: 0x0
})
);
}

if (isWithdrawCollateral) {
if (userConfig.isBorrowingAny()) {
ValidationLogic.validateHFAndLtvERC721(
reservesData,
reservesList,
userConfig,
params.otherdeed,
params.otherdeedIds,
msg.sender,
params.reservesCount,
params.oracle
);
}
}
}

function _getTokenData(uint256[] memory tokenIds)
internal
returns (DataTypes.ERC721SupplyParams[] memory tokenData)
{
tokenData = new DataTypes.ERC721SupplyParams[](tokenIds.length);
for (uint256 index = 0; index < tokenIds.length; index++) {
tokenData[index] = DataTypes.ERC721SupplyParams({
tokenId: tokenIds[index],
useAsCollateral: true
});
}
}
}
13 changes: 13 additions & 0 deletions contracts/protocol/libraries/types/DataTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,19 @@ library DataTypes {
address oracle;
}

struct OtherdeedClaimParams {
address otherdeed;
address otherdeedExpanded;
address koda;
address vessel;
uint256[] otherdeedIds;
uint256[] kodaIds;
uint256[] kodaOtherdeedIds;
bytes32[][] merkleProofs;
uint256 reservesCount;
address oracle;
}

struct ExecuteDecreaseUniswapV3LiquidityParams {
address user;
address asset;
Expand Down
43 changes: 42 additions & 1 deletion contracts/protocol/pool/PoolPositionMover.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,28 @@ contract PoolPositionMover is
ILendPool internal immutable BENDDAO_LEND_POOL;
uint256 internal constant POOL_REVISION = 149;

address immutable OTHERDEED;
address immutable OTHERDEED_EXPANDED;
address immutable KODA;
address immutable VESSEL;

constructor(
IPoolAddressesProvider addressProvider,
ILendPoolLoan benddaoLendPoolLoan,
ILendPool benddaoLendPool
ILendPool benddaoLendPool,
address otherdeed,
address otherdeedExpanded,
address koda,
address vessel
) {
ADDRESSES_PROVIDER = addressProvider;
BENDDAO_LEND_POOL_LOAN = benddaoLendPoolLoan;
BENDDAO_LEND_POOL = benddaoLendPool;

OTHERDEED = otherdeed;
OTHERDEED_EXPANDED = otherdeedExpanded;
KODA = koda;
VESSEL = vessel;
}

function movePositionFromBendDAO(uint256[] calldata loanIds)
Expand All @@ -51,6 +65,33 @@ contract PoolPositionMover is
);
}

function claimOtherExpandedAndSupply(
uint256[] calldata otherdeedIds,
uint256[] calldata kodaIds,
uint256[] calldata kodaOtherdeedIds,
bytes32[][] calldata merkleProofs
) external nonReentrant {
DataTypes.PoolStorage storage ps = poolStorage();

PositionMoverLogic.executeClaimOtherdeedAndSupply(
ps._reserves,
ps._reservesList,
ps._usersConfig[msg.sender],
DataTypes.OtherdeedClaimParams({
otherdeed: OTHERDEED,
otherdeedExpanded: OTHERDEED_EXPANDED,
koda: KODA,
vessel: VESSEL,
otherdeedIds: otherdeedIds,
kodaIds: kodaIds,
kodaOtherdeedIds: kodaOtherdeedIds,
merkleProofs: merkleProofs,
reservesCount: ps._reservesCount,
oracle: ADDRESSES_PROVIDER.getPriceOracle()
})
);
}

function getRevision() internal pure virtual override returns (uint256) {
return POOL_REVISION;
}
Expand Down
Loading