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

Cross-Currency Rollover #133

Merged
merged 27 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f01464c
feat(cross-currency-rollover): cross currency rollover contract and s…
Mouzayan May 29, 2024
af38b42
feat(cross-currency-rollover): update package json
Mouzayan May 29, 2024
f27f621
feat(cross-currency-rollover): updated yearn lock files
Mouzayan May 29, 2024
716a0a2
feat(cross-currency-rollover): update workflows test yml
Mouzayan May 29, 2024
ac12198
feat(cross-currency-rollover): print balances in script
Mouzayan May 30, 2024
030c43b
feat(cross-currency-rollover): kvk pr comments
Mouzayan May 30, 2024
22dd570
feat(cross-currency-rollover): remove flashloan. add script for princ…
Mouzayan Jun 2, 2024
1804c1a
feat(cross-currency-rollover): rename and separate function concerns
Mouzayan Jun 4, 2024
9636c04
feat(cross-currency-rollover): enable yul optimizer
Mouzayan Jun 4, 2024
591ff15
feat(cross-currency-rollover): make scripts options: with new lender …
Mouzayan Jun 4, 2024
f1e0083
feat(cross-currency-rollover): remove commented out code
Mouzayan Jun 4, 2024
279802e
feat(cross-currency-rollover): break up function to remove viair:true
Mouzayan Jun 4, 2024
3b90020
feat(cross-currency-rollover): revert change to test.yml
Mouzayan Jun 4, 2024
121605c
feat(cross-currency-rollover): keep swapparams outside of repaydata
Mouzayan Jun 5, 2024
d10f3d8
feat(cross-currency-rollover): eliminate fetchcurrentprice
Mouzayan Jun 6, 2024
5d9291a
feat(cross-currency-rollover): comment fixes
Mouzayan Jun 6, 2024
3dabfe9
feat(cross-currency-rollover): cleanup amounts.amounttoborrower and a…
Mouzayan Jun 6, 2024
a71368f
feat(cross-currency-rollover): update comment
Mouzayan Jun 6, 2024
848bda5
feat(cross-currency-rollover): add origination controller base and se…
Mouzayan Jun 7, 2024
653ed23
feat(cross-currency-rollover): add ocbase and separate out functional…
Mouzayan Jun 7, 2024
7c71949
feat(cross-currency-rollover): ocbase
Mouzayan Jun 10, 2024
0e2d23c
feat(cross-currency-rollover): ocbase
Mouzayan Jun 10, 2024
e6e9cde
feat(cross-currency-rollover): move helper functions from ocbase to oc
Mouzayan Jun 10, 2024
2c898b9
feat(cross-currency-rollover): kvk comment fixes
Mouzayan Jun 10, 2024
05b422c
feat(cross-currency-rollover): comment fixes
Mouzayan Jun 11, 2024
b1f28a5
feat(cross-currency-rollover): comment fixes
Mouzayan Jun 12, 2024
776dcc9
feat(cross-currency-rollover): kvk comment fixes
Mouzayan Jun 13, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Uses node.js 18
uses: actions/setup-node@v2
with:
node-version: 18
node-version: 18.20.3

- name: Install
run: yarn install --frozen-lockfile
Expand Down
111 changes: 111 additions & 0 deletions contracts/errors/Rollover.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

/**
* @title Rollover Errors
* @author Non-Fungible Technologies, Inc.
*
* This file contains custom errors for the cross currency rollover contract, with errors
* prefixed by "CCR_" for CrossCurrencyRollover.
* Errors located in one place to make it possible to holistically look at all
Copy link
Contributor

Choose a reason for hiding this comment

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

"Errors located in one place to make it possible to holistically look at all protocol failure cases" doesnt hold true since this is separate from all the other lending errors. What is the reasoning for making them separate? All of the other origination controller flavors are in the lending.sol file.

* protocol failure cases.
*/

// ================================== CROSS CURRENCY ROLLOVER ====================================
/// @notice All errors prefixed with CCR_, to separate from other contracts in the protocol.

/**
* @notice The flash loan callback caller is not recognized. The caller must be the flash
* loan provider.
*
* @param caller The address of the caller.
* @param lendingPool Expected address of the flash loan provider.
*/
error CCR_UnknownCaller(address caller, address lendingPool);

/**
* @notice Only the holder of the borrowerNote can rollover their loan.
*/
error CCR_CallerNotBorrower();

/**
* @notice Contract is paused, rollover operations are blocked.
*/
error CCR_Paused();

/**
* @notice The rollover contract is already in the specified pause state.
*/
error CCR_StateAlreadySet();

/**
* @notice Borrower address is not cached of the flash loan callback.
*/
error CCR_BorrowerNotCached();

/**
* @notice The borrower address saved in the rollover contract is not the same as the
* borrower address provided in the flash loan operation data. The initiator of
* the flash loan must be the rollover contract.
*
* @param providedBorrower Borrower address passed in the flash loan operation data.
* @param cachedBorrower Borrower address saved in the rollover contract.
*/
error CCR_UnknownBorrower(address providedBorrower, address cachedBorrower);

/**
* @notice The borrower state must be address(0) to initiate a rollover sequence.
*
* @param borrower The borrower address.
*/
error CCR_BorrowerNotReset(address borrower);

/**
* @notice Ensure valid loan state for loan lifecycle operations.
*
* @param state Current state of a loan according to LoanState enum.
*/
error CCR_InvalidState(uint8 state);

/**
* @notice Signer is attempting to take the wrong side of the loan.
*
* @param signer The address of the external signer.
*/
error CCR_SideMismatch(address signer);

/**
* @notice New currency should not match original loan currency.
*
* @param oldCurrency The currency of the active loan.
* @param newCurrency The currency of the new loan.
*/
error CCR_SameCurrency(address oldCurrency, address newCurrency);

/**
* @notice New collateral does not match for a loan migration request.
*
* @param oldCollateralAddress The address of the active loan's collateral.
* @param newCollateralAddress The token ID of the active loan's collateral.
* @param oldCollateralId The address of the new loan's collateral.
* @param newCollateralId The token ID of the new loan's collateral.
*/
error CCR_CollateralMismatch(
address oldCollateralAddress,
uint256 oldCollateralId,
address newCollateralAddress,
uint256 newCollateralId
);

/**
* @notice The lender specified for a migration cannot be the current borrower.
*/
error CCR_LenderIsBorrower();

/**
* @notice Zero address passed in where not allowed.
*
* @param addressType The name of the parameter for which a zero address was provided.
*/
error CCR_ZeroAddress(string addressType);
50 changes: 50 additions & 0 deletions contracts/external/uniswapV3/libraries/PoolAddress.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.18;

/// @title Provides functions for deriving a pool address from the factory, tokens, and the fee
library PoolAddress {
bytes32 internal constant POOL_INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;

/// @notice The identifying key of the pool
struct PoolKey {
address token0;
address token1;
uint24 fee;
}

/// @notice Returns PoolKey: the ordered tokens with the matched fee levels
/// @param tokenA The first token of a pool, unsorted
/// @param tokenB The second token of a pool, unsorted
/// @param fee The fee level of the pool
/// @return Poolkey The pool details with ordered token0 and token1 assignments
function getPoolKey(
address tokenA,
address tokenB,
uint24 fee
) internal pure returns (PoolKey memory) {
if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);
return PoolKey({token0: tokenA, token1: tokenB, fee: fee});
}

/// @notice Deterministically computes the pool address given the factory and PoolKey
/// @param factory The Uniswap V3 factory contract address
/// @param key The PoolKey
/// @return pool The contract address of the V3 pool
function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) {
require(key.token0 < key.token1);
pool = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encode(key.token0, key.token1, key.fee)),
POOL_INIT_CODE_HASH
)
)
)
)
);
}
}
32 changes: 32 additions & 0 deletions contracts/interfaces/ICrossCurrencyRollover.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

import "../libraries/LoanLibrary.sol";
import "../libraries/OriginationLibrary.sol";

import "./IOriginationController.sol";

interface ICrossCurrencyRollover {
// =========================== EVENTS ==========================
event PausedStateChanged(bool isPaused);
event CurrencyRollover(address indexed lender, address indexed borrower, uint256 collateralTokenId, uint256 newLoanId);

// ================== CROSS CURRENCY ROLLOVER ==================
function rolloverCrossCurrencyLoan(
uint256 oldLoanId,
LoanLibrary.LoanTerms calldata loanTerms,
address lender,
IOriginationController.Signature calldata sig,
IOriginationController.SigProperties calldata sigProperties,
LoanLibrary.Predicate[] calldata itemPredicates,
OriginationLibrary.SwapParameters calldata swapParams
) external;

function calculateProratedInterestAmount(uint256 loanId) external returns (uint256);

function fetchCurrentPrice(address tokenIn, address tokenOut, uint24 poolFee) external returns (uint256 price);

// ======================== OWNER OPS =========================
function pause(bool _pause) external;
}
14 changes: 14 additions & 0 deletions contracts/libraries/OriginationLibrary.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ library OriginationLibrary {
RolloverAmounts migrationAmounts;
}

struct SwapParameters {
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be part of ICrossCurrencyRollover, since it is only used in the cross-currency case

uint256 minAmountOut;
uint24 poolFeeTier;
}

struct CrossCurrencyRepayData {
uint256 oldLoanId;
LoanLibrary.LoanTerms newLoanTerms;
address borrower;
address lender;
RolloverAmounts rolloverAmounts;
SwapParameters swapParameters;
}

// ======================================= CONSTANTS ==============================================

/// @notice EIP712 type hash for bundle-based signatures.
Expand Down
4 changes: 4 additions & 0 deletions contracts/origination/OriginationController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ contract OriginationController is

bytes32 public constant ADMIN_ROLE = keccak256("ADMIN");
bytes32 public constant MIGRATION_MANAGER_ROLE = keccak256("MIGRATION_MANAGER");
bytes32 public constant ROLLOVER_MANAGER_ROLE = keccak256("ROLLOVER_MANAGER");

// =============== Contract References ===============

Expand Down Expand Up @@ -109,6 +110,9 @@ contract OriginationController is
_setupRole(MIGRATION_MANAGER_ROLE, msg.sender);
_setRoleAdmin(MIGRATION_MANAGER_ROLE, ADMIN_ROLE);

_setupRole(ROLLOVER_MANAGER_ROLE, msg.sender);
_setRoleAdmin(ROLLOVER_MANAGER_ROLE, ADMIN_ROLE);

originationHelpers = IOriginationHelpers(_originationHelpers);
loanCore = ILoanCore(_loanCore);
feeController = IFeeController(_feeController);
Expand Down
Loading
Loading