wormhole-lending-examples/example-2/evm/src/contracts/lendingHub/HubInterestUtilities.sol

171 lines
7.4 KiB
Solidity
Raw Normal View History

Example 2 (#28) * Set up contracts for second example (#8) Co-authored-by: gator-boi <gator-boi@users.noreply.github.com> * Set up contract state (#11) * Set up contracts for second example * Delete README * Define interface and contract state Co-authored-by: gator-boi <gator-boi@users.noreply.github.com> * Hub messages (#12) * Update HubMessages.sol * Update HubStructs.sol * finish decode msgs (#13) * Update HubMessages.sol * Update HubStructs.sol * write decode messages Co-authored-by: derpy-duck <115193320+derpy-duck@users.noreply.github.com> * Add .vscode to gitignore (#14) Co-authored-by: derpy-duck <akadaveru@guse4c-ossdev-akl1.jumpisolated.com> * Fixing some compile errors in HubMessages (#15) * Fixing some compile errors in HubMessages * Add Register Spoke method to register spokes on hub * Implement completeRegisterSpoke * Add chainId to message header, and add a check function to ensure the spoke that a message comes from is registered * Add getWormholePayload function * Remove registerSpoke as a wormhole message, and only allow on the hub as owner Co-authored-by: derpy-duck <akadaveru@guse4c-ossdev-akl1.jumpisolated.com> * Test files (#16) * Fixing some compile errors in HubMessages * Basic test Co-authored-by: derpy-duck <akadaveru@guse4c-ossdev-akl1.jumpisolated.com> * first pass at lending Hub completeDeposit (#17) * first pass at lending Hub completeDeposit * added barebones logic to completeWithdraw * add some skeleton for repay & liquidation * added some comments * Progress 12:30-1:30 * forge install: forge-std * fixed errors * derpy-ducks's fixes Co-authored-by: wrinkled-latherer Co-authored-by: derpy-duck <115193320+derpy-duck@users.noreply.github.com> * Adding encoding and decoding payload tests (#20) * Derpy duck refactor and borrow (#21) * Borrow * transfer tokens empty function * sign fix * added collateralization ratio precision * Liquidation and register msg (#19) * mock Pyth * shot myself in the foot * tried fixing comment * test * set vault and global amounts Co-authored-by: wrinkled-latherer <114771197+wrinkledLatherer@users.noreply.github.com> Co-authored-by: derpy-duck <115193320+derpy-duck@users.noreply.github.com> * cleanup (#22) * Reorganized into HubUtilities and added docstrings to HubUtilities (#23) * Reorganized into HubUtilities and added docstrings to HubUtilities * Move the helper functions from Hub into HubUtilities * Adding back a TODO * Hub docstrings (#25) * Hub specs * Fixed allowedToWithdraw to add another check of making sure that there is enough total supply in the protocol before going ahead with a withdrawal * Writing hub tests (#26) * dump of testing * makefile * evm: fix token transfer encoding * fixed slice issues, deposit test working * tad * refactored testing code to be cleaner * updated tests with index accrual precision updated * Seperated tests into helper file and main file * enable manual oracle setting * begin borrow testing * Borrow test passes! * resolved some todos * addressed low decimals exploit * add comment Co-authored-by: wrinkledLatherer Co-authored-by: A5 Pickle <a5-pickle@users.noreply.github.com> * Test updates (#27) * Fix compile error * Max decimals * test updates * Changing the tests that fail to fail tests * Cleaning up price code in tests * CLEAN testing file! * Removing some redundant comments * Repay tests * make decimals part of adaptive state * added some comments * fixed max liquidation bonus setting * fix liquidation test Co-authored-by: wrinkledLatherer * Spoke (#24) * Implementation of spoke methods without tokenbridge * Added token bridge portion * Implementation of spoke methods without tokenbridge * Added token bridge portion * Remove merge conflict * Check valid address * Swap token bridge payload to wormhole payload * Lending detail (#29) * add interest rate model params to asset info * add liquidation max portion repayable as param * add reserve factor usage * add multiple collat ratios * figure out some todos Co-authored-by: wrinkledLatherer <asuresh@dub2t-btcdevl1.w2k.jumptrading.com> * Derpy duck changes (#30) * Move functions from Spoke to SpokeUtilities * Fix address we are signing wormhole message with, and add a 'check duplicates' function for asset arrays passed into liquidation * Token transfers (#31) * implement transferTokens function * Approve token transfers and fix compile errors * Token transfers more * Testing prank mint (#32) * Testing prank mint * Remove changes to MyERC20 * fixed fake minting * Changed hardcoded addresses to refer to asset[0] and asset[1], and also changed testFail to use vm.expectRevert Co-authored-by: wrinkledLatherer * First integration test (#33) * Real oracle (#34) * Mock Pyth working * add confidence computation to price * add pyth docs link in comments * made nConf intervals a param * consolidated diff oracleMode update price feed fns into one fn Co-authored-by: wrinkledLatherer * Cleaned up price calls (#36) * More integration tests (#35) * Slight cleaning of first integration test * some fixes * attempt token bridge integration test deposit * Working deposit testgit add .git add .! * Nicer hub only tests * Fix compile errors * initialize publishtime * remove comments * Decimals (#37) * decimal overflow error huh * pushed some console msgs * tests pass! * put division at the end for rounding reasons Co-authored-by: wrinkledLatherer <asuresh@dub2t-btcdevl1.w2k.jumptrading.com> * Cleaning integration tests (#39) * add the integration tests * Reorganization of test file progress * Testing files giant reorg * Combine deposit repay withdraw borrow test methods * Integration tests pass! * Remove completeRegisterAsset and all asset state on spoke * requires in the test methods * Verify sender is spoke for token bridge messages * lint fixes (#40) * Prettier formatting, and normalize hub amounts in test before checking validity (#41) * Native token transfer (#38) * add initial native token tfer tests * add WETH interface * got native token tfer working * added tests for repay native * added reversion for repayments * get rid of some unnecessary TODOs * Repay check * testRDBL passes; removed some redundant requires Co-authored-by: wrinkledLatherer <wrinkledLatherer> Co-authored-by: derpy-duck <115193320+derpy-duck@users.noreply.github.com> * Derpy duck testing improvements (#44) * doLiquidate and liquidation checks * move nativeeth requires into helper method, and combine doAction and doActionNative * AddAsset struct around adding assets * Move set price to helper function * Combine test methods with their fail counterparts * liquidation additional require statement about global supply * Hub spoke cleanup combining methods (#45) * Remove unnecessary variables * Combine deposit borrow withdraw and repay structs and methods on hub; prevents relayer from choosing which functions to relay message to * Remove unused test utility files related to creating signed WH messages for testing purposes * Remove unnecessary spoke methods setters adn getters * Remove unnecessary spoke imports * Far cleaner Hub file * Generalize HubMessages and HubStructs, and account for dust in Hub logging (#46) * Remove transfer result struct (#47) * Generalize HubMessages and HubStructs, and account for dust in Hub logging * remove one struct * remove one struct * Hub specs (#48) * Remove unnecessary test method * Rename nConf to priceStandardDeviations * Specs * fix parse error * subtract messageFee from amount when doing check * Careful thinking about divisions as it relates to interest rates (#49) * More specs (#50) * More specs * Add price specs * prettier formatting * docstring fix * Successful interest rate and price conf tests (#52) * Spoke spec for constructor * Correct typo in spec * Tidying and interest rate additions (#54) * tidy up checks in completeAction on hub * add some documentation around the double round up in allowedToRepay * add piecewise linear interest rate model * remove rate intercept and rate coefficient * add checks for kinks and rates to be valid * Test helper fix (#53) * Consider dust in test, and use public getters or acocunt balances (#55) * evm: fix yarn.lock * evm: fix guardian set index * evm: fix Makefile * evm: fix stack too deep * evm: fix README * evm: remove lib/forge-std Co-authored-by: Reptile <43194093+gator-boi@users.noreply.github.com> Co-authored-by: gator-boi <gator-boi@users.noreply.github.com> Co-authored-by: wrinkledLatherer <114771197+wrinkledLatherer@users.noreply.github.com> Co-authored-by: derpy-duck <akadaveru@guse4c-ossdev-akl1.jumpisolated.com> Co-authored-by: A5 Pickle <a5-pickle@users.noreply.github.com> Co-authored-by: wrinkledLatherer <asuresh@dub2t-btcdevl1.w2k.jumptrading.com>
2023-01-25 10:12:07 -08:00
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "../HubSpokeStructs.sol";
import "./HubGetters.sol";
import "./HubSetters.sol";
contract HubInterestUtilities is HubSpokeStructs, HubGetters, HubSetters {
/*
*
* The following three functions describe the Interest Rate Model of the whole protocol!
* TODO: IMPORTANT! Substitute this function out for whatever desired interest rate model you wish to have
*
*/
/**
* @notice Assets accrue interest over time, so at any given point in time the value of an asset is (amount of asset on day 1) * (the amount of interest that has accrued).
* This function updates both the deposit and borrow interest accrual indices of the asset.
*
* @param assetAddress - The asset to update the interest accrual indices of
*/
function updateAccrualIndices(address assetAddress) internal {
setInterestAccrualIndices(assetAddress, getCurrentAccrualIndices(assetAddress));
setLastActivityBlockTimestamp(assetAddress, block.timestamp);
}
function getCurrentAccrualIndices(address assetAddress) internal view returns (AccrualIndices memory) {
uint256 lastActivityBlockTimestamp = getLastActivityBlockTimestamp(assetAddress);
uint256 secondsElapsed = block.timestamp - lastActivityBlockTimestamp;
uint256 deposited = getTotalAssetsDeposited(assetAddress);
AccrualIndices memory accrualIndices = getInterestAccrualIndices(assetAddress);
if ((secondsElapsed != 0) && (deposited != 0)) {
uint256 borrowed = getTotalAssetsBorrowed(assetAddress);
PiecewiseInterestRateModel memory interestRateModel = getInterestRateModel(assetAddress);
uint256 interestFactor = computeSourceInterestFactor(secondsElapsed, deposited, borrowed, interestRateModel);
AssetInfo memory assetInfo = getAssetInfo(assetAddress);
uint256 reserveFactor = assetInfo.interestRateModel.reserveFactor;
uint256 reservePrecision = assetInfo.interestRateModel.reservePrecision;
accrualIndices.borrowed += interestFactor;
accrualIndices.deposited +=
(interestFactor * (reservePrecision - reserveFactor) * borrowed) / reservePrecision / deposited;
}
return accrualIndices;
}
function computeSourceInterestFactor(
uint256 secondsElapsed,
uint256 deposited,
uint256 borrowed,
PiecewiseInterestRateModel memory interestRateModel
) internal view returns (uint256) {
if (deposited == 0) {
return 0;
}
uint256[] memory kinks = interestRateModel.kinks;
uint256[] memory rates = interestRateModel.rates;
uint i = 0;
uint256 interestRate = 0;
while (borrowed * interestRateModel.ratePrecision > deposited * kinks[i]) {
interestRate = rates[i];
i += 1;
if (i == rates.length) {
return rates[i-1];
}
}
// if zero borrows and nonzero deposits, then set interest rate for period to the rate intercept i.e. first kink; ow linearly interpolate between kinks
if (i==0) {
interestRate = rates[0];
}
else {
interestRate += (rates[i] - rates[i-1]) * ((borrowed * interestRateModel.ratePrecision - kinks[i-1] * deposited) / deposited) / (kinks[i] - kinks[i-1]);
Example 2 (#28) * Set up contracts for second example (#8) Co-authored-by: gator-boi <gator-boi@users.noreply.github.com> * Set up contract state (#11) * Set up contracts for second example * Delete README * Define interface and contract state Co-authored-by: gator-boi <gator-boi@users.noreply.github.com> * Hub messages (#12) * Update HubMessages.sol * Update HubStructs.sol * finish decode msgs (#13) * Update HubMessages.sol * Update HubStructs.sol * write decode messages Co-authored-by: derpy-duck <115193320+derpy-duck@users.noreply.github.com> * Add .vscode to gitignore (#14) Co-authored-by: derpy-duck <akadaveru@guse4c-ossdev-akl1.jumpisolated.com> * Fixing some compile errors in HubMessages (#15) * Fixing some compile errors in HubMessages * Add Register Spoke method to register spokes on hub * Implement completeRegisterSpoke * Add chainId to message header, and add a check function to ensure the spoke that a message comes from is registered * Add getWormholePayload function * Remove registerSpoke as a wormhole message, and only allow on the hub as owner Co-authored-by: derpy-duck <akadaveru@guse4c-ossdev-akl1.jumpisolated.com> * Test files (#16) * Fixing some compile errors in HubMessages * Basic test Co-authored-by: derpy-duck <akadaveru@guse4c-ossdev-akl1.jumpisolated.com> * first pass at lending Hub completeDeposit (#17) * first pass at lending Hub completeDeposit * added barebones logic to completeWithdraw * add some skeleton for repay & liquidation * added some comments * Progress 12:30-1:30 * forge install: forge-std * fixed errors * derpy-ducks's fixes Co-authored-by: wrinkled-latherer Co-authored-by: derpy-duck <115193320+derpy-duck@users.noreply.github.com> * Adding encoding and decoding payload tests (#20) * Derpy duck refactor and borrow (#21) * Borrow * transfer tokens empty function * sign fix * added collateralization ratio precision * Liquidation and register msg (#19) * mock Pyth * shot myself in the foot * tried fixing comment * test * set vault and global amounts Co-authored-by: wrinkled-latherer <114771197+wrinkledLatherer@users.noreply.github.com> Co-authored-by: derpy-duck <115193320+derpy-duck@users.noreply.github.com> * cleanup (#22) * Reorganized into HubUtilities and added docstrings to HubUtilities (#23) * Reorganized into HubUtilities and added docstrings to HubUtilities * Move the helper functions from Hub into HubUtilities * Adding back a TODO * Hub docstrings (#25) * Hub specs * Fixed allowedToWithdraw to add another check of making sure that there is enough total supply in the protocol before going ahead with a withdrawal * Writing hub tests (#26) * dump of testing * makefile * evm: fix token transfer encoding * fixed slice issues, deposit test working * tad * refactored testing code to be cleaner * updated tests with index accrual precision updated * Seperated tests into helper file and main file * enable manual oracle setting * begin borrow testing * Borrow test passes! * resolved some todos * addressed low decimals exploit * add comment Co-authored-by: wrinkledLatherer Co-authored-by: A5 Pickle <a5-pickle@users.noreply.github.com> * Test updates (#27) * Fix compile error * Max decimals * test updates * Changing the tests that fail to fail tests * Cleaning up price code in tests * CLEAN testing file! * Removing some redundant comments * Repay tests * make decimals part of adaptive state * added some comments * fixed max liquidation bonus setting * fix liquidation test Co-authored-by: wrinkledLatherer * Spoke (#24) * Implementation of spoke methods without tokenbridge * Added token bridge portion * Implementation of spoke methods without tokenbridge * Added token bridge portion * Remove merge conflict * Check valid address * Swap token bridge payload to wormhole payload * Lending detail (#29) * add interest rate model params to asset info * add liquidation max portion repayable as param * add reserve factor usage * add multiple collat ratios * figure out some todos Co-authored-by: wrinkledLatherer <asuresh@dub2t-btcdevl1.w2k.jumptrading.com> * Derpy duck changes (#30) * Move functions from Spoke to SpokeUtilities * Fix address we are signing wormhole message with, and add a 'check duplicates' function for asset arrays passed into liquidation * Token transfers (#31) * implement transferTokens function * Approve token transfers and fix compile errors * Token transfers more * Testing prank mint (#32) * Testing prank mint * Remove changes to MyERC20 * fixed fake minting * Changed hardcoded addresses to refer to asset[0] and asset[1], and also changed testFail to use vm.expectRevert Co-authored-by: wrinkledLatherer * First integration test (#33) * Real oracle (#34) * Mock Pyth working * add confidence computation to price * add pyth docs link in comments * made nConf intervals a param * consolidated diff oracleMode update price feed fns into one fn Co-authored-by: wrinkledLatherer * Cleaned up price calls (#36) * More integration tests (#35) * Slight cleaning of first integration test * some fixes * attempt token bridge integration test deposit * Working deposit testgit add .git add .! * Nicer hub only tests * Fix compile errors * initialize publishtime * remove comments * Decimals (#37) * decimal overflow error huh * pushed some console msgs * tests pass! * put division at the end for rounding reasons Co-authored-by: wrinkledLatherer <asuresh@dub2t-btcdevl1.w2k.jumptrading.com> * Cleaning integration tests (#39) * add the integration tests * Reorganization of test file progress * Testing files giant reorg * Combine deposit repay withdraw borrow test methods * Integration tests pass! * Remove completeRegisterAsset and all asset state on spoke * requires in the test methods * Verify sender is spoke for token bridge messages * lint fixes (#40) * Prettier formatting, and normalize hub amounts in test before checking validity (#41) * Native token transfer (#38) * add initial native token tfer tests * add WETH interface * got native token tfer working * added tests for repay native * added reversion for repayments * get rid of some unnecessary TODOs * Repay check * testRDBL passes; removed some redundant requires Co-authored-by: wrinkledLatherer <wrinkledLatherer> Co-authored-by: derpy-duck <115193320+derpy-duck@users.noreply.github.com> * Derpy duck testing improvements (#44) * doLiquidate and liquidation checks * move nativeeth requires into helper method, and combine doAction and doActionNative * AddAsset struct around adding assets * Move set price to helper function * Combine test methods with their fail counterparts * liquidation additional require statement about global supply * Hub spoke cleanup combining methods (#45) * Remove unnecessary variables * Combine deposit borrow withdraw and repay structs and methods on hub; prevents relayer from choosing which functions to relay message to * Remove unused test utility files related to creating signed WH messages for testing purposes * Remove unnecessary spoke methods setters adn getters * Remove unnecessary spoke imports * Far cleaner Hub file * Generalize HubMessages and HubStructs, and account for dust in Hub logging (#46) * Remove transfer result struct (#47) * Generalize HubMessages and HubStructs, and account for dust in Hub logging * remove one struct * remove one struct * Hub specs (#48) * Remove unnecessary test method * Rename nConf to priceStandardDeviations * Specs * fix parse error * subtract messageFee from amount when doing check * Careful thinking about divisions as it relates to interest rates (#49) * More specs (#50) * More specs * Add price specs * prettier formatting * docstring fix * Successful interest rate and price conf tests (#52) * Spoke spec for constructor * Correct typo in spec * Tidying and interest rate additions (#54) * tidy up checks in completeAction on hub * add some documentation around the double round up in allowedToRepay * add piecewise linear interest rate model * remove rate intercept and rate coefficient * add checks for kinks and rates to be valid * Test helper fix (#53) * Consider dust in test, and use public getters or acocunt balances (#55) * evm: fix yarn.lock * evm: fix guardian set index * evm: fix Makefile * evm: fix stack too deep * evm: fix README * evm: remove lib/forge-std Co-authored-by: Reptile <43194093+gator-boi@users.noreply.github.com> Co-authored-by: gator-boi <gator-boi@users.noreply.github.com> Co-authored-by: wrinkledLatherer <114771197+wrinkledLatherer@users.noreply.github.com> Co-authored-by: derpy-duck <akadaveru@guse4c-ossdev-akl1.jumpisolated.com> Co-authored-by: A5 Pickle <a5-pickle@users.noreply.github.com> Co-authored-by: wrinkledLatherer <asuresh@dub2t-btcdevl1.w2k.jumptrading.com>
2023-01-25 10:12:07 -08:00
}
return (getInterestAccrualIndexPrecision() * secondsElapsed * interestRate / interestRateModel.ratePrecision) / 365 / 24 / 60 / 60;
}
/*
*
* End Interest Rate Model
*
*/
/**
* @notice Assets accrue interest over time, so at any given point in time the value of an asset is (amount of asset on day 1) * (the amount of interest that has accrued).
*
* @param denormalizedAmount - The true amount of an asset
* @param interestAccrualIndex - The amount of interest that has accrued, multiplied by getInterestAccrualIndexPrecision().
* So, (interestAccrualIndex/interestAccrualIndexPrecision) represents the interest accrued (this is initialized to 1 at the start of the protocol)
* @return {uint256} The normalized amount of the asset
*/
function normalizeAmount(uint256 denormalizedAmount, uint256 interestAccrualIndex, Round round)
public
view
returns (uint256)
{
return divide(denormalizedAmount * getInterestAccrualIndexPrecision(), interestAccrualIndex, round);
}
/**
* @notice Similar to 'normalizeAmount', takes a normalized value (amount of an asset) and denormalizes it.
*
* @param normalizedAmount - The normalized amount of an asset
* @param interestAccrualIndex - The amount of interest that has accrued, multiplied by getInterestAccrualIndexPrecision().
* @return {uint256} The true amount of the asset
*/
function denormalizeAmount(uint256 normalizedAmount, uint256 interestAccrualIndex, Round round)
public
view
returns (uint256)
{
return divide(normalizedAmount * interestAccrualIndex, getInterestAccrualIndexPrecision(), round);
}
/**
* @notice Get a user's account balance in an asset
*
* @param vaultOwner - the address of the user
* @param assetAddress - the address of the asset
* @return a struct with 'deposited' field and 'borrowed' field for the amount deposited and borrowed of the asset
* multiplied by 10^decimal for that asset. Values are denormalized.
*/
function getUserBalance(address vaultOwner, address assetAddress) public view returns (VaultAmount memory) {
VaultAmount memory normalized = getVaultAmounts(vaultOwner, assetAddress);
AccrualIndices memory interestAccrualIndex = getCurrentAccrualIndices(assetAddress);
return VaultAmount({
deposited: denormalizeAmount(normalized.deposited, interestAccrualIndex.deposited, Round.DOWN),
borrowed: denormalizeAmount(normalized.borrowed, interestAccrualIndex.borrowed, Round.UP)
});
}
/**
* @notice Get the protocol's global balance in an asset
*
* @param assetAddress - the address of the asset
* @return a struct with 'deposited' field and 'borrowed' field for the amount deposited and borrowed of the asset
* multiplied by 10^decimal for that asset. Values are denormalized.
*/
function getGlobalBalance(address assetAddress) public view returns (VaultAmount memory) {
VaultAmount memory normalized = getGlobalAmounts(assetAddress);
AccrualIndices memory interestAccrualIndex = getCurrentAccrualIndices(assetAddress);
return VaultAmount({
deposited: denormalizeAmount(normalized.deposited, interestAccrualIndex.deposited, Round.DOWN),
borrowed: denormalizeAmount(normalized.borrowed, interestAccrualIndex.borrowed, Round.UP)
});
}
/**
* @notice Divide helper function, for rounding
*
* @param dividend - the dividend
* @param divisor - the divisor
* @param round - Whether or not to round up (Round.UP) or round down (Round.DOWN)
* @return dividend/divisor, rounded appropriately
*/
function divide(uint256 dividend, uint256 divisor, Round round) internal pure returns (uint256) {
uint256 modulo = dividend % divisor;
uint256 quotient = dividend / divisor;
if (modulo == 0 || round == Round.DOWN) {
return quotient;
}
return quotient + 1;
}
}