Skip to content

Commit

Permalink
ignore this SEC im jking
Browse files Browse the repository at this point in the history
  • Loading branch information
nutty committed Feb 1, 2022
1 parent c99292c commit 68833b2
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 4 deletions.
7 changes: 7 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[default]
src = 'src'
out = 'out'
libs = ['lib']
remappings = ['ds-test/=lib/ds-test/src/']

# See more config options https://github.com/gakonst/foundry/tree/master/config
4 changes: 0 additions & 4 deletions src/Contract.sol

This file was deleted.

223 changes: 223 additions & 0 deletions src/Vault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12;

import "./libraries/safemath.sol";
import "./libraries/IERC20.sol";
import "./libraries/yearnVault.sol";

// Special thanks to twiiter@prism0x for being way smarter than me with this distribution algo
// https://solmaz.io/2019/02/24/scalable-reward-changing/


/// @title PonzuVault :: Single asset token vault
/// @author Nuhhtyy
/// @notice Single asset vault, no liqudations synthetic self repaying over-collaterized loans
/// All Yeild Generated from Yearn Vaults
/// @dev 1% Fee taken via synth
contract pVault {

using SafeMath for uint;

// #########################
// ## ##
// ## State ##
// ## ##
// #########################

// ENSURE COLLATERAL AND SYNTH TOKEN REVERTS ON FAILED TRANSFER
IERC20 internal collateral;
IERC20 internal synthetic;
yVault internal yearnVault;
address feeCollector;

mapping (address => uint) public deposits;
mapping (address => uint) public debt;

uint256 public totalDebt;
uint256 public totalDeposits;
uint256 public totalYearnDeposited;
uint256 public feesAccumlated;

// sum of all distribution events ( yeild / totalDeposits )
// scaled 1e10.. As long as rewards accumlated between distributions
// are greater than 1/1e10 totalDeposits , distribute() should return a nonzero value
uint256 internal yeildPerDeposit;
uint256 internal SCALAR;

// sum of changes of deposit * yeildPerToken
mapping (address => uint) internal depositTracker;

// Too bad using a uint16 in storage doesnt even save gas :(
// Say I wont pack it into a struct I dare you
// 75% BP
uint16 maxLTV = 7500;

// 1.25% BP ... Used to incentivize LPs
uint16 fee = 125;

constructor(address _synthetic, address _yearnVault, address _collateral, address _feeCollector) {

yearnVault = yVault(_yearnVault);
collateral = IERC20(_collateral);
synthetic = IERC20(_synthetic);
feeCollector = _feeCollector;
}

// #########################
// ## ##
// ## External ##
// ## ##
// #########################

function deposit(uint amount) external {

deposits[msg.sender] = deposits[msg.sender].add(amount);
totalDeposits = totalDeposits.add(amount);

// Im sorry this is ugly omg
depositTracker[msg.sender] =
depositTracker[msg.sender]
.add(yeildPerDeposit.mul(amount).div(SCALAR));

uint depositing = amount.mul(5000).div(10000);
totalYearnDeposited = totalYearnDeposited.add(depositing);

// Make sure Collateral tokens Revert
collateral.transferFrom(msg.sender, address(this), amount);

// deposit 50% to yVault
yearnVault.deposit(depositing);
}

function withdraw(uint amount) external {

require( withdrawable(msg.sender) >= amount, "Amount too high");
deposits[msg.sender] = deposits[msg.sender].sub(amount);
totalDeposits = totalDeposits.sub(amount);

depositTracker[msg.sender] =
depositTracker[msg.sender]
.sub(yeildPerDeposit.mul(amount).div(SCALAR));

if ( amount > collateral.balanceOf(address(this)) ) {

withdrawNeeded(amount);

}

collateral.transfer(msg.sender, amount);

}

function incurDebt(uint amount) external {

require( debt[msg.sender].add(amount) <= deposits[msg.sender].mul(maxLTV).div(10000) );

debt[msg.sender] = debt[msg.sender].add(amount);
totalDebt = totalDebt.add(amount);

uint feeAdjust = amount.mul(fee).div(10000);
feesAccumlated = feesAccumlated.add( amount.sub(feeAdjust) );

synthetic.mint(msg.sender, feeAdjust);

}

function repayDebtSynth(uint amount) external {

require ( debt[msg.sender] >= amount );
debt[msg.sender] = debt[msg.sender].sub(amount);
totalDebt = totalDebt.sub(amount);

synthetic.transferFrom(msg.sender, address(this), amount); //change to burn

}

function repayDebtAsset(uint amount) external {

require ( debt[msg.sender] >= amount );
debt[msg.sender] = debt[msg.sender].sub(amount);
totalDebt = totalDebt.sub(amount);

collateral.transferFrom(msg.sender, address(this), amount);

}

function claimFees() external {

require(msg.sender == feeCollector);

uint fees = feesAccumlated;
feesAccumlated = 0;

synthetic.mint(msg.sender, fees);

}

// #########################
// ## ##
// ## Public ##
// ## ##
// #########################

function harvestAndDistribute() public {

uint yeild = getYeild();
yearnVault.withdraw(yeild);

yeildPerDeposit = yeildPerDeposit
.add(yeild.mul(SCALAR).div(totalDeposits));

}

//does not change user debt or overall debt
//Will likely change this somehow.. not sure yet
function burnSynth(uint amount) public {

totalDeposits = totalDeposits.sub(amount);

synthetic.transferFrom(msg.sender, address(0), amount);
collateral.transfer(msg.sender, amount);

}

// #########################
// ## ##
// ## Internal ##
// ## ##
// #########################

function getYeild() internal returns (uint) {

uint price = yearnVault.getPricePerFullShare();
uint totalClaimable = yearnVault.balanceOf(address(this)).mul(price);

return totalClaimable.sub(totalYearnDeposited);

}

function withdrawable(address who) internal view returns (uint) {

uint yeild = deposits[who]
.mul(yeildPerDeposit).div(SCALAR)
.sub(depositTracker[msg.sender]);

uint colSubDebt = deposits[who].sub(debt[who]);

return colSubDebt.add(yeild);

}

function withdrawNeeded(uint amount) internal {

uint tokenNeeded = amount.sub( collateral.balanceOf(address(this)) );
uint price = yearnVault.getPricePerFullShare();

// tokenNeeded / sharePrice = sharesNeeded
uint adjusted = tokenNeeded.div(price);
totalYearnDeposited = totalYearnDeposited.sub(adjusted);
yearnVault.withdraw(adjusted);

}

}
15 changes: 15 additions & 0 deletions src/libraries/IERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12;

interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function mint(address who, uint amount) external;

event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
48 changes: 48 additions & 0 deletions src/libraries/safemath.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12;

/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {

/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}

/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return a / b;
}

/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}

/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}
16 changes: 16 additions & 0 deletions src/libraries/yearnVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12;

// yearn vaults act as an ERC20
interface yVault {

function deposit(uint _amount) external;

//returns # of tokens per share
function getPricePerFullShare() external view returns (uint);

function withdraw(uint _shares) external;

function balanceOf(address who) external returns (uint);

}
Empty file added src/pToken.sol
Empty file.

0 comments on commit 68833b2

Please sign in to comment.