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

Dev ex/cf build script #665

Open
wants to merge 99 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
87b7fb0
initial b.protocol commit
yaronvel Jun 23, 2021
ab6a53a
lp token
yaronvel Jun 26, 2021
02670c5
fuzzy share + staking
yaronvel Jun 26, 2021
dfd272b
fuzzy price formula test
yaronvel Jun 26, 2021
a596c94
share + eth test
yaronvel Jun 27, 2021
abe744d
withdraw with eth
yaronvel Jun 27, 2021
a5dc53d
4% max test
yaronvel Jun 27, 2021
9d10595
price > eth balance
yaronvel Jun 27, 2021
38bb5b9
more tests
yaronvel Jun 29, 2021
8d072fa
set params test
yaronvel Jun 29, 2021
072acde
front end support
yaronvel Jun 29, 2021
509b28c
transfer
yaronvel Jun 29, 2021
91070b5
pickle support
yaronvel Jun 30, 2021
c823767
remove erc20 operations from bamm
yaronvel Jun 30, 2021
7859259
compiler warning cleanups
yaronvel Jun 30, 2021
6a63feb
events
yaronvel Jun 30, 2021
3af7bcf
linter
yaronvel Jun 30, 2021
4d82e3e
function order according to linter
yaronvel Jun 30, 2021
ecb8e74
audit fixes
yaronvel Jul 7, 2021
5120787
more audit fixes
yaronvel Jul 7, 2021
72b4611
temp
Jul 7, 2021
3459b04
Merge pull request #1 from backstop-protocol/audit-fixes
yaronvel Jul 7, 2021
0093256
papers
yaronvel Jul 7, 2021
3bf6933
Merge pull request #2 from backstop-protocol/audit-fixes
yaronvel Jul 7, 2021
4f9a9d0
add smart contract assessment by Fixed Point Solutions
kmbarry1 Jul 7, 2021
aa327cc
Merge pull request #3 from Fixed-Point-Solutions/FPS-assessment
yaronvel Jul 7, 2021
d93ad9d
Delete TODO.txt
yaronvel Jul 7, 2021
b1e9a60
ownable - allow transfer ownership
yaronvel Jul 8, 2021
ca76864
stabilityDeposit.poolShare
Jul 11, 2021
60bb75a
cleanUp
Jul 11, 2021
92f716f
LQTY reward
Jul 11, 2021
1626072
Changing liquidation gain to BAMM ETH
Jul 12, 2021
6b01e9f
working state
Jul 12, 2021
62155bb
remove the Claim LQTY and move ETH to Trove BTN
Jul 12, 2021
d51f03e
text change
Jul 12, 2021
f2ce78d
text change
Jul 12, 2021
d1f3668
minor layout change
Jul 12, 2021
a279980
unlock
Jul 13, 2021
1dc6bc7
bamm pool share
Jul 14, 2021
c801f6b
lens
yaronvel Jul 15, 2021
4d50628
Merge pull request #4 from backstop-protocol/B-Lens
yaronvel Jul 15, 2021
03847c8
working state
Jul 19, 2021
3fef0e1
styleFix: whale friendly layout :)
Jul 19, 2021
91cf169
hide away really small rounding errors
Jul 19, 2021
5e35116
Merge remote-tracking branch 'origin/main' into B-frontend
Jul 19, 2021
054e632
adding bLens contract and reading LQTY reward from it
Jul 19, 2021
2001922
unlock bamm modal
Jul 19, 2021
64bb4f7
refactor:
Jul 20, 2021
a01f8b1
bugFix
Jul 20, 2021
8404868
improvment
Jul 20, 2021
68ed95f
validatind network connection
Jul 21, 2021
8d64582
minor style change
Jul 21, 2021
2e8cc41
CF worker
Jul 22, 2021
64d9509
adding b.protocol icon
Jul 22, 2021
ded16eb
adding a link to the terms
Jul 22, 2021
5630ca7
Merge pull request #5 from liquity/main
shmuel-web Jul 25, 2021
32478e5
Merge branch 'main-2' into feature/b-forntend-3
Jul 25, 2021
c572ff5
hide:
Jul 25, 2021
d5609b2
hide:
Jul 25, 2021
a296243
hide:
Jul 25, 2021
765de76
Refactor:
Jul 25, 2021
8f24999
mainnet address
Jul 25, 2021
bb7aa61
text change
Jul 25, 2021
84a1317
allowance pending spiner
Jul 25, 2021
9ad1d50
blocking mainnet
Jul 25, 2021
facbb0e
display logo
Jul 26, 2021
9140e9b
text change
Jul 26, 2021
3bcb7b5
Merge pull request #7 from liquity/main
yaronvel Jul 28, 2021
67aa903
merge main
Jul 29, 2021
5c83e39
yarnlock
Jul 29, 2021
5c38524
Stability Pool 1234
Jul 29, 2021
9c08bc3
hide BAMM Pool share
Jul 29, 2021
4a9b3e0
ETH tooltip
Jul 29, 2021
4561ce2
hide ETH if its Negligible
Jul 29, 2021
e11d722
cleanUp
Jul 29, 2021
d2ce882
fonts
Jul 30, 2021
02dc382
static assets
Jul 30, 2021
b147e2b
connect page
Jul 30, 2021
7a38dfa
responsiveness
Jul 30, 2021
e27c1bc
add devDependencies
Aug 1, 2021
6de5a57
style
Aug 1, 2021
eb1b4f0
change validation order
Aug 1, 2021
3c33919
text changes
Aug 1, 2021
4d4b297
dispalying eth and lusd witdraw amount
Aug 1, 2021
2fece7f
removing collateral gain (eth gain)
Aug 1, 2021
69a1e90
small text and style tweaks
Aug 2, 2021
6f52823
BugFix: storeUpdate changes wrong values
Aug 2, 2021
381262e
trimm roundeing error
Aug 2, 2021
4c91136
metamask mobile fix
Aug 2, 2021
af2237b
[mainnet]
Aug 2, 2021
2be43b4
text
Aug 2, 2021
8187934
showOverlay when SP transaction is in progress
Aug 2, 2021
6ba906d
full stop
Aug 2, 2021
4941b13
stability pool 1
Aug 2, 2021
cb71fd4
BugFix: withdraw
Aug 2, 2021
2151ba2
cf-build script
Aug 4, 2021
4976861
typo
Aug 4, 2021
e9d4e87
added generate static to the build step
Aug 8, 2021
135c307
Update remove-iframe-deny.js
yaronvel Aug 8, 2021
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
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
]
},
"scripts": {
"cf-build": "yarn && run-s build:dev-frontend",
"build": "run-s build:*",
"build:dev-frontend": "yarn workspace @liquity/dev-frontend build",
"build:subgraph": "yarn workspace @liquity/subgraph build",
Expand All @@ -53,10 +54,7 @@
"prepare:lib-base": "yarn workspace @liquity/lib-base prepare",
"prepare:lib-ethers": "yarn workspace @liquity/lib-ethers prepare",
"prepare:lib-react": "yarn workspace @liquity/lib-react prepare",
"prepare:lib-subgraph": "yarn workspace @liquity/lib-subgraph prepare",
"prepare:providers": "yarn workspace @liquity/providers prepare",
"prepare:subgraph": "yarn workspace @liquity/subgraph prepare",
"prepare:docs": "run-s docs",
"rebuild": "run-s prepare build",
"release": "run-s release:*",
"release:delete-dev-deployments": "yarn workspace @liquity/lib-ethers delete-dev-deployments",
Expand Down
231 changes: 231 additions & 0 deletions packages/contracts/contracts/B.Protocol/BAMM.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.6.11;

import "./../StabilityPool.sol";
import "./CropJoinAdapter.sol";
import "./PriceFormula.sol";
import "./../Interfaces/IPriceFeed.sol";
import "./../Dependencies/IERC20.sol";
import "./../Dependencies/SafeMath.sol";
import "./../Dependencies/Ownable.sol";
import "./../Dependencies/AggregatorV3Interface.sol";


contract BAMM is CropJoinAdapter, PriceFormula, Ownable {
using SafeMath for uint256;

AggregatorV3Interface public immutable priceAggregator;
IERC20 public immutable LUSD;
StabilityPool immutable public SP;

address payable public immutable feePool;
uint public constant MAX_FEE = 100; // 1%
uint public fee = 0; // fee in bps
uint public A = 20;
uint public constant MIN_A = 20;
uint public constant MAX_A = 200;

uint public immutable maxDiscount; // max discount in bips

address public immutable frontEndTag;

uint constant public PRECISION = 1e18;

event ParamsSet(uint A, uint fee);
event UserDeposit(address indexed user, uint lusdAmount, uint numShares);
event UserWithdraw(address indexed user, uint lusdAmount, uint ethAmount, uint numShares);
event RebalanceSwap(address indexed user, uint lusdAmount, uint ethAmount, uint timestamp);

constructor(
address _priceAggregator,
address payable _SP,
address _LUSD,
address _LQTY,
uint _maxDiscount,
address payable _feePool,
address _fronEndTag)
public
CropJoinAdapter(_LQTY)
{
priceAggregator = AggregatorV3Interface(_priceAggregator);
LUSD = IERC20(_LUSD);
SP = StabilityPool(_SP);

feePool = _feePool;
maxDiscount = _maxDiscount;
frontEndTag = _fronEndTag;
}

function setParams(uint _A, uint _fee) external onlyOwner {
require(_fee <= MAX_FEE, "setParams: fee is too big");
require(_A >= MIN_A, "setParams: A too small");
require(_A <= MAX_A, "setParams: A too big");

fee = _fee;
A = _A;

emit ParamsSet(_A, _fee);
}

function fetchPrice() public view returns(uint) {
uint chainlinkDecimals;
uint chainlinkLatestAnswer;
uint chainlinkTimestamp;

// First, try to get current decimal precision:
try priceAggregator.decimals() returns (uint8 decimals) {
// If call to Chainlink succeeds, record the current decimal precision
chainlinkDecimals = decimals;
} catch {
// If call to Chainlink aggregator reverts, return a zero response with success = false
return 0;
}

// Secondly, try to get latest price data:
try priceAggregator.latestRoundData() returns
(
uint80 /* roundId */,
int256 answer,
uint256 /* startedAt */,
uint256 timestamp,
uint80 /* answeredInRound */
)
{
// If call to Chainlink succeeds, return the response and success = true
chainlinkLatestAnswer = uint(answer);
chainlinkTimestamp = timestamp;
} catch {
// If call to Chainlink aggregator reverts, return a zero response with success = false
return 0;
}

if(chainlinkTimestamp + 1 hours < now) return 0; // price is down

uint chainlinkFactor = 10 ** chainlinkDecimals;
return chainlinkLatestAnswer.mul(PRECISION) / chainlinkFactor;
}

function deposit(uint lusdAmount) external {
// update share
uint lusdValue = SP.getCompoundedLUSDDeposit(address(this));
uint ethValue = SP.getDepositorETHGain(address(this)).add(address(this).balance);

uint price = fetchPrice();
require(ethValue == 0 || price > 0, "deposit: chainlink is down");

uint totalValue = lusdValue.add(ethValue.mul(price) / PRECISION);

// this is in theory not reachable. if it is, better halt deposits
// the condition is equivalent to: (totalValue = 0) ==> (total = 0)
require(totalValue > 0 || total == 0, "deposit: system is rekt");

uint newShare = PRECISION;
if(total > 0) newShare = total.mul(lusdAmount) / totalValue;

// deposit
require(LUSD.transferFrom(msg.sender, address(this), lusdAmount), "deposit: transferFrom failed");
SP.provideToSP(lusdAmount, frontEndTag);

// update LP token
mint(msg.sender, newShare);

emit UserDeposit(msg.sender, lusdAmount, newShare);
}

function withdraw(uint numShares) external {
uint lusdValue = SP.getCompoundedLUSDDeposit(address(this));
uint ethValue = SP.getDepositorETHGain(address(this)).add(address(this).balance);

uint lusdAmount = lusdValue.mul(numShares).div(total);
uint ethAmount = ethValue.mul(numShares).div(total);

// this withdraws lusd, lqty, and eth
SP.withdrawFromSP(lusdAmount);

// update LP token
burn(msg.sender, numShares);

// send lusd and eth
if(lusdAmount > 0) LUSD.transfer(msg.sender, lusdAmount);
if(ethAmount > 0) {
(bool success, ) = msg.sender.call{ value: ethAmount }(""); // re-entry is fine here
require(success, "withdraw: sending ETH failed");
}

emit UserWithdraw(msg.sender, lusdAmount, ethAmount, numShares);
}

function addBps(uint n, int bps) internal pure returns(uint) {
require(bps <= 10000, "reduceBps: bps exceeds max");
require(bps >= -10000, "reduceBps: bps exceeds min");

return n.mul(uint(10000 + bps)) / 10000;
}

function getSwapEthAmount(uint lusdQty) public view returns(uint ethAmount, uint feeEthAmount) {
uint lusdBalance = SP.getCompoundedLUSDDeposit(address(this));
uint ethBalance = SP.getDepositorETHGain(address(this)).add(address(this).balance);

uint eth2usdPrice = fetchPrice();
if(eth2usdPrice == 0) return (0, 0); // chainlink is down

uint ethUsdValue = ethBalance.mul(eth2usdPrice) / PRECISION;
uint maxReturn = addBps(lusdQty.mul(PRECISION) / eth2usdPrice, int(maxDiscount));

uint xQty = lusdQty;
uint xBalance = lusdBalance;
uint yBalance = lusdBalance.add(ethUsdValue.mul(2));

uint usdReturn = getReturn(xQty, xBalance, yBalance, A);
uint basicEthReturn = usdReturn.mul(PRECISION) / eth2usdPrice;

if(ethBalance < basicEthReturn) basicEthReturn = ethBalance; // cannot give more than balance
if(maxReturn < basicEthReturn) basicEthReturn = maxReturn;

ethAmount = addBps(basicEthReturn, -int(fee));
feeEthAmount = basicEthReturn.sub(ethAmount);
}

// get ETH in return to LUSD
function swap(uint lusdAmount, uint minEthReturn, address payable dest) public returns(uint) {
(uint ethAmount, uint feeAmount) = getSwapEthAmount(lusdAmount);

require(ethAmount >= minEthReturn, "swap: low return");

LUSD.transferFrom(msg.sender, address(this), lusdAmount);
SP.provideToSP(lusdAmount, frontEndTag);

if(feeAmount > 0) feePool.transfer(feeAmount);
(bool success, ) = dest.call{ value: ethAmount }(""); // re-entry is fine here
require(success, "swap: sending ETH failed");

emit RebalanceSwap(msg.sender, lusdAmount, ethAmount, now);

return ethAmount;
}

// kyber network reserve compatible function
function trade(
IERC20 /* srcToken */,
uint256 srcAmount,
IERC20 /* destToken */,
address payable destAddress,
uint256 /* conversionRate */,
bool /* validate */
) external payable returns (bool) {
return swap(srcAmount, 0, destAddress) > 0;
}

function getConversionRate(
IERC20 /* src */,
IERC20 /* dest */,
uint256 srcQty,
uint256 /* blockNumber */
) external view returns (uint256) {
(uint ethQty, ) = getSwapEthAmount(srcQty);
return ethQty.mul(PRECISION) / srcQty;
}

receive() external payable {}
}
58 changes: 58 additions & 0 deletions packages/contracts/contracts/B.Protocol/BLens.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.6.11;

import "./BAMM.sol";
import "./../Dependencies/SafeMath.sol";


contract BLens {
function add(uint256 x, uint256 y) public pure returns (uint256 z) {
require((z = x + y) >= x, "ds-math-add-overflow");
}
function sub(uint256 x, uint256 y) public pure returns (uint256 z) {
require((z = x - y) <= x, "ds-math-sub-underflow");
}
function mul(uint256 x, uint256 y) public pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
}
function divup(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(x, sub(y, 1)) / y;
}
uint256 constant WAD = 10 ** 18;
function wmul(uint256 x, uint256 y) public pure returns (uint256 z) {
z = mul(x, y) / WAD;
}
function wdiv(uint256 x, uint256 y) public pure returns (uint256 z) {
z = mul(x, WAD) / y;
}
function wdivup(uint256 x, uint256 y) public pure returns (uint256 z) {
z = divup(mul(x, WAD), y);
}
uint256 constant RAY = 10 ** 27;
function rmul(uint256 x, uint256 y) public pure returns (uint256 z) {
z = mul(x, y) / RAY;
}
function rmulup(uint256 x, uint256 y) public pure returns (uint256 z) {
z = divup(mul(x, y), RAY);
}
function rdiv(uint256 x, uint256 y) public pure returns (uint256 z) {
z = mul(x, RAY) / y;
}

function getUnclaimedLqty(address user, BAMM bamm, ERC20 token) external returns(uint) {
// trigger bamm (p)lqty claim
bamm.withdraw(0);

if(bamm.total() == 0) return 0;

// duplicate harvest logic
uint crop = sub(token.balanceOf(address(bamm)), bamm.stock());
uint share = add(bamm.share(), rdiv(crop, bamm.total()));

uint last = bamm.crops(user);
uint curr = rmul(bamm.stake(user), share);
if(curr > last) return curr - last;
return 0;
}
}
41 changes: 41 additions & 0 deletions packages/contracts/contracts/B.Protocol/ChainlinkTestnet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.6.11;

import "./../TestContracts/PriceFeedTestnet.sol";

/*
* PriceFeed placeholder for testnet and development. The price is simply set manually and saved in a state
* variable. The contract does not connect to a live Chainlink price feed.
*/
contract ChainlinkTestnet {

PriceFeedTestnet feed;
uint time = 0;

constructor(PriceFeedTestnet _feed) public {
feed = _feed;
}

function decimals() external pure returns(uint) {
return 18;
}

function setTimestamp(uint _time) external {
time = _time;
}

function latestRoundData() external view returns
(
uint80 /* roundId */,
int256 answer,
uint256 /* startedAt */,
uint256 timestamp,
uint80 /* answeredInRound */
)
{
answer = int(feed.getPrice());
if(time == 0 ) timestamp = now;
else timestamp = time;
}
}
Loading