diff --git a/package-lock.json b/package-lock.json index 4b2afd3..080a47d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bprotocol-react-client", - "version": "1.0.47", + "version": "1.0.49", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index dea04bf..7743945 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bprotocol-react-client", - "version": "1.0.47", + "version": "1.0.49", "private": true, "dependencies": { "@cloudflare/kv-asset-handler": "^0.1.0", diff --git a/src/assets/coin-icons/Rari.png b/src/assets/coin-icons/Rari.png new file mode 100644 index 0000000..5f94d84 Binary files /dev/null and b/src/assets/coin-icons/Rari.png differ diff --git a/src/components/stability-pool/Logo.js b/src/components/stability-pool/Logo.js index 598bf9f..5e22da7 100644 --- a/src/components/stability-pool/Logo.js +++ b/src/components/stability-pool/Logo.js @@ -3,7 +3,7 @@ import React from "react"; export default function Logo() { return (
- + diff --git a/src/components/stability-pool/SpActionBox.js b/src/components/stability-pool/SpActionBox.js index 0f85467..edcc671 100644 --- a/src/components/stability-pool/SpActionBox.js +++ b/src/components/stability-pool/SpActionBox.js @@ -93,12 +93,18 @@ const Unlock = observer(({grantAllowance, hasAllowance, allowanceInProgress, ass ) }) +const isErc20 = symbol => ["ETH"].indexOf(symbol) == -1 + const SpFooterContent = observer((props) => { - const {footerIsOpen, txInProgress, action, err, inputErrMsg, inputIsValid, inputIsInvalid, hash, walletBalance, closeFooter, asset, onInputChange, val, collaterals, withdrawValues} = props.store + const {footerIsOpen, txInProgress, action, err, inputErrMsg, inputIsValid, inputIsInvalid, hash, walletBalance, closeFooter, asset, onInputChange, val, collaterals, withdrawValues, config} = props.store const {grantAllowance, hasAllowance, allowanceInProgress, collPercnet, usdPercnet } = props.store let doAction = action === "Deposit" ? props.store.deposit : props.store.withdraw const singleWithdrawValue = parseFloat(collPercnet) < 0.01 const onMobile = isMobile() + const allowanceNeeded = action == "Deposit" && isErc20(asset) + const {denominator} = config + const prefix = !denominator ? "$" : "" + const suffix = denominator ? denominator : "" return (
closeFooter()}/> @@ -124,7 +130,7 @@ const SpFooterContent = observer((props) => { disabled={inputIsInvalid} onClick={()=> doAction(val)}>{action}} - {action == "Deposit" && } + {allowanceNeeded && }
{action == "Deposit" &&
@@ -138,17 +144,17 @@ const SpFooterContent = observer((props) => { {action == "Withdraw" &&
Current Withdraw Value{singleWithdrawValue ? ": " : "s:"} {singleWithdrawValue && - $ + {prefix} {suffix} }
{!singleWithdrawValue &&

{usdPercnet}% in {asset}
- $ + {prefix} {suffix}

{collPercnet}% in collateral ({collaterals.map(coll => {coll.symbol} )})
- $
+ {prefix}
{suffix}

}
} @@ -287,8 +293,21 @@ class SpActionBox extends Component { render() { const {asset, userShareInUsd, walletBalance, tvl, footerIsOpen, action, openFooter, closeFooter, reward, config, collaterals, apr} = this.props.store - const { collateralName, platformName } = config + let { collateralName, description } = config + description = description || collateralName + " stability pool" const onMobile = isMobile() + let totalApr = apr + if(typeof apr === "object") { + totalApr = apr.reduce((acc, o)=> acc + parseFloat(o.value), 0).toString() + } + let aprExplainer = "The APR is identical to vestafinance.xyz" + if(typeof apr === "object"){ + aprExplainer = apr.reduce((acc, o)=> acc + o.name + ": " + parseFloat(o.value).toFixed(2) + "% + ", "") + aprExplainer = aprExplainer.slice(0, aprExplainer.length - 3) + } + const {denominator} = config + const prefix = !denominator ? "$" : "" + const suffix = denominator ? denominator : "" return (
@@ -299,21 +318,21 @@ class SpActionBox extends Component { {asset} - {collateralName && {collateralName} stability pool} + {description && {description}} {onMobile &&
}
-
$
+
{prefix} {suffix}
Balance
-
%
-
APR
+
%
+
APR
diff --git a/src/components/stability-pool/View.js b/src/components/stability-pool/View.js index 68deb4f..769f28b 100644 --- a/src/components/stability-pool/View.js +++ b/src/components/stability-pool/View.js @@ -3,7 +3,6 @@ import WhiteBgViewIcon from "../../assets/view-icon.svg"; import BlacBgViewIcon from "../../assets/view-icon-opeq-bg.svg"; import userStore from "../../stores/user.store" -// TODO: userStore.scannerUrl export default function View(props) { const {hash} = props const {blockExplorer} = userStore diff --git a/src/components/style-components/AnimateNumericalString.js b/src/components/style-components/AnimateNumericalString.js index f5babd3..06640cc 100644 --- a/src/components/style-components/AnimateNumericalString.js +++ b/src/components/style-components/AnimateNumericalString.js @@ -34,7 +34,7 @@ export default class AnimateNumericalString extends Component{ config={{duration}} from={{ number: this.state.from }} to={{ number: this.state.to }}> - {({number}) => {number.interpolate(x=> truncateToDecimals(parseFloat(x)), decimals)}} + {({number}) => {number.interpolate(x=> truncateToDecimals(parseFloat(x), decimals))}} ) } diff --git a/src/components/style-components/TooltipIcon.js b/src/components/style-components/TooltipIcon.js index d1eba0f..a0b26d5 100644 --- a/src/components/style-components/TooltipIcon.js +++ b/src/components/style-components/TooltipIcon.js @@ -10,7 +10,7 @@ return ( border: "1.5px solid var(--contrast)", borderRadius: "50%" }} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19 19"> - + diff --git a/src/containers/Vesta.js b/src/containers/Vesta.js index 1105ea7..c1753c5 100644 --- a/src/containers/Vesta.js +++ b/src/containers/Vesta.js @@ -6,6 +6,7 @@ import routerStore from "../stores/router.store" import SpActionBox from "../components/stability-pool/SpActionBox" import Navbar from "../components/stability-pool/Navbar" import vestaStore from "../stores/vesta.store" +import fuseStore from "../stores/fuse.store" import VestaInfoPage from "../components/vesta/VestaInfoPage" import userStore from "../stores/user.store" @@ -20,31 +21,18 @@ class Vesta extends Component { } render() { - const stabilityPools = [ - { - asset: 'USDC', - amount: '1000.43', - apy: '5.4', - walletBalance: '5000000.12' - }, - { - asset: 'USDT', - amount: '404.21', - apy: '6.7', - walletBalance: '5000.12' - }, - - ] const hideInfoPage = userStore.loggedIn || userStore.connecting + const loading = vestaStore.loading && fuseStore.loading return (
{hideInfoPage &&
- {vestaStore.loading &&
+ {loading &&
loading...
} - {vestaStore.stabilityPools.map((sp, i)=> )} + {!loading && fuseStore.stabilityPools.map((sp, i)=> )} + {!loading && vestaStore.stabilityPools.map((sp, i)=> )}
} {!hideInfoPage && } diff --git a/src/lib/fuse/abi.js b/src/lib/fuse/abi.js new file mode 100644 index 0000000..9e0733f --- /dev/null +++ b/src/lib/fuse/abi.js @@ -0,0 +1,569 @@ +export const abi = { + "erc20": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "chainId_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "guy", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": true, + "inputs": [ + { + "indexed": true, + "internalType": "bytes4", + "name": "sig", + "type": "bytes4" + }, + { + "indexed": true, + "internalType": "address", + "name": "usr", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "arg1", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "arg2", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "LogNote", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "usr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "usr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "guy", + "type": "address" + } + ], + "name": "deny", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "usr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "move", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "allowed", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "usr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "pull", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "usr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "push", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "guy", + "type": "address" + } + ], + "name": "rely", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "wards", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "bamm": [{"inputs":[{"internalType":"address","name":"_cBorrow","type":"address"},{"internalType":"bool","name":"_isCETH","type":"bool"},{"internalType":"uint256","name":"_maxDiscount","type":"uint256"},{"internalType":"address payable","name":"_feePool","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenOwner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"A","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"callerFee","type":"uint256"}],"name":"ParamsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"lusdAmount","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RebalanceSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"lusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numShares","type":"uint256"}],"name":"UserDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"lusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numShares","type":"uint256"}],"name":"UserWithdraw","type":"event"},{"inputs":[],"name":"A","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LUSD","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_A","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CALLER_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_A","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ICToken","name":"ctoken","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"feed","type":"address"}],"name":"addCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cBorrow","outputs":[{"internalType":"contract ICToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"callerFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ICToken","name":"cTokenBorrowed","type":"address"},{"internalType":"contract ICToken","name":"cTokenCollateral","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"canLiquidate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"collateralDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"collaterals","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"lusdAmount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numShares","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"withdrawCollateral","type":"bool"},{"internalType":"uint256","name":"minLusd","type":"uint256"}],"name":"efficientWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feePool","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"fetchPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCollateralValue","outputs":[{"internalType":"bool","name":"succ","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"xQty","type":"uint256"},{"internalType":"uint256","name":"xBalance","type":"uint256"},{"internalType":"uint256","name":"yBalance","type":"uint256"},{"internalType":"uint256","name":"A","type":"uint256"}],"name":"getReturn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"uint256","name":"A","type":"uint256"}],"name":"getSumFixedPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"lusdQty","type":"uint256"},{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getSwapAmount","outputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isCETH","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"contract ICToken","name":"collateral","type":"address"}],"name":"liquidateBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lusdDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDiscount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"priceAggregators","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ICToken","name":"ctoken","type":"address"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_A","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_callerFee","type":"uint256"}],"name":"setParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lusdAmount","type":"uint256"},{"internalType":"contract IERC20","name":"returnToken","type":"address"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"address payable","name":"dest","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numShares","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}], + "cToken": [{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"cTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldAdminFeeMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAdminFeeMantissa","type":"uint256"}],"name":"NewAdminFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ComptrollerInterface","name":"oldComptroller","type":"address"},{"indexed":false,"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"NewComptroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFuseFeeMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFuseFeeMantissa","type":"uint256"}],"name":"NewFuseFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":false,"internalType":"address","name":"newImplementation","type":"address"}],"name":"NewImplementation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"reduceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":false,"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"_becomeImplementation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"_prepare","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newAdminFeeMantissa","type":"uint256"}],"name":"_setAdminFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"implementation_","type":"address"},{"internalType":"bool","name":"allowResign","type":"bool"},{"internalType":"bytes","name":"becomeImplementationData","type":"bytes"}],"name":"_setImplementationSafe","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"_setNameAndSymbol","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"_withdrawAdminFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"_withdrawFuseFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"adminFeeMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"fuseFeeMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"uint256","name":"reserveFactorMantissa_","type":"uint256"},{"internalType":"uint256","name":"adminFeeMantissa_","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint256","name":"reserveFactorMantissa_","type":"uint256"},{"internalType":"uint256","name":"adminFeeMantissa_","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract InterestRateModel","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isCEther","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isCToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"contract CToken","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"mint","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolSeizeShareMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"repayBorrow","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"repayBorrowBehalf","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalAdminFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalFuseFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}], + "wrapper": [{"inputs":[{"internalType":"address","name":"_masterChef","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"bfETH","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"fETH","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"masterChef","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"proxies","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}], + "masterChef": [{"inputs":[{"internalType":"contract IERC20","name":"_pickle","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"picklePerSecond","type":"uint256"}],"name":"LogPicklePerSecond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":true,"internalType":"contract IERC20","name":"lpToken","type":"address"},{"indexed":true,"internalType":"contract IRewarder","name":"rewarder","type":"address"}],"name":"LogPoolAddition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":true,"internalType":"contract IRewarder","name":"rewarder","type":"address"},{"indexed":false,"internalType":"bool","name":"overwrite","type":"bool"}],"name":"LogSetPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"lastRewardTime","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"lpSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accPicklePerShare","type":"uint256"}],"name":"LogUpdatePool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"PICKLE","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"contract IERC20","name":"_lpToken","type":"address"},{"internalType":"contract IRewarder","name":"_rewarder","type":"address"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"calls","type":"bytes[]"},{"internalType":"bool","name":"revertOnFail","type":"bool"}],"name":"batch","outputs":[{"internalType":"bool[]","name":"successes","type":"bool[]"},{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lpToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"pids","type":"uint256[]"}],"name":"massUpdatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"migrator","outputs":[{"internalType":"contract IMigratorChef","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingPickle","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"picklePerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"uint128","name":"accPicklePerShare","type":"uint128"},{"internalType":"uint64","name":"lastRewardTime","type":"uint64"},{"internalType":"uint64","name":"allocPoint","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"pools","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewarder","outputs":[{"internalType":"contract IRewarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"contract IRewarder","name":"_rewarder","type":"address"},{"internalType":"bool","name":"overwrite","type":"bool"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMigratorChef","name":"_migrator","type":"address"}],"name":"setMigrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_pickle","type":"address"}],"name":"setPickle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_picklePerSecond","type":"uint256"}],"name":"setPicklePerSecond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalAllocPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"bool","name":"direct","type":"bool"},{"internalType":"bool","name":"renounce","type":"bool"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"updatePool","outputs":[{"components":[{"internalType":"uint128","name":"accPicklePerShare","type":"uint128"},{"internalType":"uint64","name":"lastRewardTime","type":"uint64"},{"internalType":"uint64","name":"allocPoint","type":"uint64"}],"internalType":"struct MiniChefV2.PoolInfo","name":"pool","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"int256","name":"rewardDebt","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawAndHarvest","outputs":[],"stateMutability":"nonpayable","type":"function"}], +} \ No newline at end of file diff --git a/src/lib/fuse/config.js b/src/lib/fuse/config.js new file mode 100644 index 0000000..b556a6a --- /dev/null +++ b/src/lib/fuse/config.js @@ -0,0 +1,25 @@ + +const poolsByChain = { + + "Arbitrum Testnet": [], + "Arbitrum One": [ + { + poolAddress: "0x51fBf83818e4Fa195fD5D395a63fCfB5C45d9565", + tokenAddress: "0x0000000000000000000000000000000000000000", + denominator: "ETH", + tokenName: "ETH", + collateralName: "Rari", + description: "Rari stability pool 44", + decimals: 18, + bammAddress: "0x94fd843E77fe67A18d52E0AD0C9713C5a9399ef4", + rewardAddress: "0x965772e0E9c84b6f359c8597C891108DcF1c5B1A", + wrapperAddress: "0xEb6276Fd4D8B05104AeF4246d84D7840CB964cC8", + masterChefAddress: "0x7Ecc7163469F37b777d7B8F45A667314030ACe24", + masterChefPID: 15 + }, + ], +} + +export const getPools = (chain) => { + return poolsByChain[chain] || [] +} \ No newline at end of file diff --git a/src/lib/fuse/interface.js b/src/lib/fuse/interface.js new file mode 100644 index 0000000..55b8542 --- /dev/null +++ b/src/lib/fuse/interface.js @@ -0,0 +1,362 @@ +import Web3 from "web3" +import { abi } from "./abi" +import axios from "axios" +const {toBN, BN, fromWei, toWei} = Web3.utils + +const maxAllowance = new BN("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16) +export const isETH = (tokenAddress) => tokenAddress === "0x0000000000000000000000000000000000000000" +const _1e18 = toBN('10').pow(toBN('18')) + +export const normlize = (n, decimals) => { + let wei = toBN(n); // eslint-disable-line + const negative = wei.lt(toBN("0")); // eslint-disable-line + const base = toBN("1" + ("0".repeat(decimals))) + const options = {}; + + if (negative) { + wei = wei.mul(new BN(-1)); + } + + let fraction = wei.mod(base).toString(10); // eslint-disable-line + + while (fraction.length < decimals) { + fraction = `0${fraction}`; + } + + if (!options.pad) { + fraction = fraction.match(/^([0-9]*[1-9]|0)(0*)/)[1]; + } + + let whole = wei.div(base).toString(10); // eslint-disable-line + + if (options.commify) { + whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); + } + + let value = `${whole}${fraction == '0' ? '' : `.${fraction}`}`; // eslint-disable-line + + if (negative) { + value = `-${value}`; + } + + return value; +} + +export const denormlize = (n, decimals) => { + const base = toBN("1" + ("0".repeat(decimals))) + + // Is it negative? + const negative = (n.substring(0, 1) === '-') + if (negative) { + n = n.substring(1) + } + + if (n === '.') { throw new Error(`while converting number ${n} to wei, invalid value`) } + + // Split it into a whole and fractional part + const comps = n.split('.') + if (comps.length > 2) { throw new Error(`[ethjs-unit] while converting number ${n} to wei, too many decimal points`) } + + let whole = comps[0], fraction = comps[1] + + if (!whole) { whole = '0' } + if (!fraction) { fraction = '0' } + if (fraction.length > decimals) { throw new Error(`[ethjs-unit] while converting number ${n} to wei, too many decimal places`) } + + while (fraction.length < decimals) { + fraction += '0' + } + whole = new BN(whole) + fraction = new BN(fraction) + let wei = (whole.mul(base)).add(fraction) + + if (negative) { + wei = wei.mul(new BN(-1)) + } + + return new BN(wei.toString(10), 10) +} + +const GAS_LIMIT = { gasLimit: "1000000" } + +export const getDecimals = ({web3, tokenAddress}) => { + const { Contract } = web3.eth + const erc20 = new Contract(abi.erc20, tokenAddress) + return erc20.methods.decimals().call() +} + +export const getAllowance = async ({web3, user, tokenAddress, poolAddress}) => { + if(isETH(tokenAddress)){ + return maxAllowance.toString() + } + const { Contract } = web3.eth + const erc20 = new Contract(abi.erc20, tokenAddress) + return await erc20.methods.allowance(user, poolAddress).call() +} + +export const grantAllowance = ({web3, tokenAddress, poolAddress}) => { + const { Contract } = web3.eth + const erc20 = new Contract(abi.erc20, tokenAddress) + + return erc20.methods.approve(poolAddress, maxAllowance) +} + +export const getWalletBallance = async ({web3, user, tokenAddress}) => { + let balance + if(isETH(tokenAddress)){ + balance = await web3.eth.getBalance(user) + } else { + const { Contract } = web3.eth + const erc20 = new Contract(abi.erc20, tokenAddress) + balance = await erc20.methods.balanceOf(user).call() + } + return balance +} + +export const deposit = (context, amount) => { + const {web3, wrapperAddress, decimals, tokenAddress} = context + if(isETH(tokenAddress)){ + return depositEth(context) + } + const { Contract } = web3.eth + const bammWrapper = new Contract(abi.wrapper, wrapperAddress) + const depositAmount = denormlize(amount, decimals) + return bammWrapper.methods.deposit(depositAmount) +} + +const depositEth = ({web3, wrapperAddress}) => { + const { Contract } = web3.eth + const bammWrapper = new Contract(abi.wrapper, wrapperAddress) + return bammWrapper.methods.deposit() +} + +const userProxyCache = {} + +const getUserProxy = async ({web3, user, wrapperAddress}) => { + if(userProxyCache[user]){ + return userProxyCache[user] + } + const { Contract } = web3.eth + const bammWrapper = new Contract(abi.wrapper, wrapperAddress) + const proxyAccount = await bammWrapper.methods.proxies(user).call(GAS_LIMIT) + if(proxyAccount){ + userProxyCache[user] = proxyAccount + } + return proxyAccount +} + +const getUserInfo = async (context) => { + const proxyAccount = await getUserProxy(context) + const {web3, masterChefPID, masterChefAddress} = context + const { Contract } = web3.eth + const masterChef = new Contract(abi.masterChef, masterChefAddress) + const userInfo = await masterChef.methods.userInfo(masterChefPID, proxyAccount).call(GAS_LIMIT) + + return userInfo +} + +export const getTvl = async(context) => { + try{ + const { web3, bammAddress, tokenAddress } = context + const { Contract } = web3.eth + const bamm = new Contract(abi.bamm, bammAddress) + + const [{amount: tokenValue}, {succ: success, value: collateralValue}] = await Promise.all([ + getUserInfo(context), + bamm.methods.getCollateralValue().call() + ]) + + if(!success){ + throw new Error("getTvl: failed to fetch collateral value") + } + const tvl = toBN(tokenValue).add(toBN(collateralValue)).toString() + let usdRatio, collRatio; + if (tvl == "0"){ + usdRatio = "0" + collRatio = "0" + }else{ + usdRatio = normlize((toBN(tokenValue).mul(toBN(1e18))).div(toBN(tvl)).toString(), 18) + collRatio = normlize((toBN(collateralValue).mul(toBN(1e18))).div(toBN(tvl)).toString(), 18) + } + + return { + tvl, + usdRatio, + collRatio + } + } catch(e) { + console.error(e) + } +} + +const getApy = (rate) => { + // Calculating the APY Using Rate Per Block + // https://compound.finance/docs#protocol-math + const blockIntrest = parseFloat(fromWei(rate)) + const blocksPerDay = 6570 // based on 4 blocks occurring every minute + const daysPerYear = 365 + + const APY = ((((blockIntrest * blocksPerDay + 1) ** daysPerYear - 1))) * 100 + return APY.toString() +} + +const getUserShareInEth = async(context, share) => { + const {web3, userAddress, bammAddress, masterChefAddress, wrapperAddress} = context + const { Contract } = web3.eth + const bamm = new Contract(abi.bamm, bammAddress) + const wrapper = new Contract(abi.wrapper, wrapperAddress) + const fEthAddress = await wrapper.methods.fETH().call() + const fETH = new Contract(abi.cToken, fEthAddress) + + const bammBal = await fETH.methods.balanceOf(bammAddress).call() + const { value: bammCollBal, succ} = await bamm.methods.getCollateralValue().call() + if(!succ){ + throw new Error("failed to get bamb collateral value") + } + const bammTotal = toBN(bammBal).add(toBN(bammCollBal)) + const bfEthAddress = await wrapper.methods.bfETH().call() + const bfETH = new Contract(abi.erc20, bfEthAddress) + const bfEthTotalSupply = await bfETH.methods.totalSupply().call() + const userFETHBal = toBN(bammTotal).mul(toBN(share)).div(toBN(bfEthTotalSupply)).toString() + const fEth2EthExchangeRate = await fETH.methods.exchangeRateStored().call() + const userShare = (toBN(userFETHBal).mul(toBN(fEth2EthExchangeRate))).div(_1e18) + return userShare +} + +export const usdToShare = async (context, withdrawAmount) => { + const {decimals} = context + const {amount: bammShare} = await getUserInfo(context) + const depositEthAmount = await getUserShareInEth(context, bammShare) + const share = toBN(denormlize(withdrawAmount, decimals)).mul(toBN(bammShare)).div(depositEthAmount) + return share.toString() +} + +export const withdraw = ({web3, wrapperAddress}, amountInShares) => { + + const { Contract } = web3.eth + const bammWrapper = new Contract(abi.wrapper, wrapperAddress) + return bammWrapper.methods.withdraw(amountInShares) +} + +export const getUserShareInUsd = async(context) => { + const {amount: bammShare} = await getUserInfo(context) + const usdVal = await getUserShareInEth(context, bammShare) + return usdVal.toString() +} + +export const getSymbol = (web3, tokenAddress) => { + if (tokenAddress == "0x0000000000000000000000000000000000000000"){ // handel ETH + return "ETH" + } + const { Contract } = web3.eth + const erc20 = new Contract(abi.erc20, tokenAddress) + return erc20.methods.symbol().call() +} + +export const getAssetDistrobution = async({web3, poolAddress, user}, assetAddress ) => { + throw new Error(`function not yet implemented`) + + let balancePromise; + if (assetAddress == "0x0000000000000000000000000000000000000000"){ // handel ETH + balancePromise = web3.eth.getBalance(poolAddress) + } else { + const { Contract } = web3.eth + const erc20 = new Contract(abi.erc20, assetAddress) + balancePromise = erc20.methods.balanceOf(user).call() + } + + const [poolBalance, symbol] = await Promise.all([ + balancePromise, + getSymbol(web3, assetAddress) + ]) + + return { + assetAddress, + poolBalance, + symbol + } +} + +export const getCollaterals = async(context) => { + return [] + const { web3, poolAddress } = context + const { Contract } = web3.eth + const bamm = new Contract(abi.bamm, poolAddress) + const promises = [] + for (let i = 0; i < 10; i++) { + const promise = bamm.methods.collaterals(i).call() + .then(address => getAssetDistrobution(context, address)) + .catch(err => null) + promises.push(promise) + } + const collaterals = (await Promise.all(promises)) + .filter(x=> x) + return collaterals +} + +export const getReward = async(context) => { + const {web3, user, masterChefAddress, masterChefPID, rewardAddress} = context + + const { Contract } = web3.eth + const masterChef = new Contract(abi.masterChef, masterChefAddress) + const erc20 = new Contract(abi.erc20, rewardAddress) + const proxyAccount = await getUserProxy(context) + const [reward, symbol, decimal, balance] = await Promise.all([ + masterChef.methods.pendingPickle(masterChefPID, proxyAccount).call(), + getSymbol(web3, rewardAddress), + getDecimals({web3, tokenAddress: rewardAddress}), + erc20.methods.balanceOf(user).call() + ]) + + return { + unclaimed: normlize(reward, decimal), + symbol, + balance: normlize(balance, decimal), + } + +} + +export const claimReward = async (context) => { + const {web3, wrapper} = context + const { Contract } = web3.eth + const bammWrapper = new Contract(abi.wrapper, wrapper) + + return bammWrapper.methods.withdraw("0") +} + +export const getApr = async (context) => { + const {web3, wrapperAddress, bammAddress, masterChefAddress, masterChefPID} = context + const { Contract } = web3.eth + + const masterChef = new Contract(abi.masterChef, masterChefAddress) + const bamm = new Contract(abi.bamm, bammAddress) + const bammWrapper = new Contract(abi.wrapper, wrapperAddress) + const fEthAddress = await bammWrapper.methods.fETH().call() + const fETH = new Contract(abi.cToken, fEthAddress) + const supplyRatePerBlock = await fETH.methods.supplyRatePerBlock().call() + const lendingAPY = getApy(supplyRatePerBlock) + // masterChef pickle reward + + const bammShare = await bamm.methods.balanceOf(masterChefAddress).call() + const totalBammInEth = await getUserShareInEth(context, bammShare) + const totalAllocPoint = await masterChef.methods.totalAllocPoint().call() + + const {allocPoint} = await masterChef.methods.poolInfo(masterChefPID).call() + + const picklePerSecond = await masterChef.methods.picklePerSecond().call() + const picklePriceInEth = (await axios.get('https://api.coingecko.com/api/v3/simple/price?ids=pickle-finance&vs_currencies=ETH')).data["pickle-finance"].eth.toString() + const pickleApy = toBN(allocPoint).mul(toBN(picklePerSecond)).div(toBN(totalAllocPoint)).mul(toBN((365 * 24 * 60 * 60).toString())) + const picklApyInEth = pickleApy.mul(toBN(toWei(picklePriceInEth))).div(_1e18) + const pickleApyForPool = parseInt((toBN(picklApyInEth).mul(toBN("10000")).div(toBN(totalBammInEth))).toString()) / 100 + + // rari pool admin fee + const borrowRatePerBlock = toWei(parseFloat(getApy(await fETH.methods.borrowRatePerBlock().call())).toFixed(18)) + const adminFeeMantissa = await fETH.methods.adminFeeMantissa().call() + const adminFee = fromWei((toBN(borrowRatePerBlock).mul(toBN(adminFeeMantissa))).div(_1e18)) + + return [ + { name: "Rari APY", value: lendingAPY }, + { name: "Rari admin fees", value: adminFee }, + { name: "Pickle Reward", value: pickleApyForPool} + ] +} \ No newline at end of file diff --git a/src/lib/vesta/config.js b/src/lib/vesta/config.js index 0e06f00..313ea99 100644 --- a/src/lib/vesta/config.js +++ b/src/lib/vesta/config.js @@ -1,14 +1,5 @@ -// TODO add support for platform name, link, docs, - const poolsByChain = { - // "kovan": [ - // { - // poolAddress: "0xEcF1b3903D8596b3B78AD624e88C65829D78b7a4", - // tokenAddress: "0x6FA3b05777dae34e95FaFd4852FF5D89c0cECF18", - // tokenName: "LUSD", - // decimals: 7 - // } - // ], + "Arbitrum Testnet": [ { poolAddress: "0xd09a277D75Ce0fA4C76ACaE5423876cD85c9f9f0", diff --git a/src/lib/vesta/interface.js b/src/lib/vesta/interface.js index 331af5f..ef61544 100644 --- a/src/lib/vesta/interface.js +++ b/src/lib/vesta/interface.js @@ -267,7 +267,6 @@ export const getCollaterals = async(context) => { } export const getReward = async({web3, user, lensAddress, poolAddress, rewardAddress}) => { - // todo fetch unclaimed reward if(!lensAddress){ return null } diff --git a/src/stores/fuse.store.js b/src/stores/fuse.store.js new file mode 100644 index 0000000..6a17f5e --- /dev/null +++ b/src/stores/fuse.store.js @@ -0,0 +1,364 @@ +/** + * @format + */ +import { makeAutoObservable, runInAction } from "mobx" +import {getPools} from "../lib/fuse/config" +import * as Interface from "../lib/fuse/interface" +import userStore from "./user.store" +import { ApiAction } from "../lib/ApiHelper" +import Web3 from "web3" +const {toBN} = Web3.utils + +export const stringToFixed = (string, numbersAfterTheDeciamlPoint) => { + const decimalPointIndex = string.indexOf(".") + if(decimalPointIndex === -1){ + return string + } + return string.slice(0, decimalPointIndex + numbersAfterTheDeciamlPoint) +} + +const reallyLargeAllowance = toBN("8888888888888888888888888888888888888888888888888888888888888888", 16) +const wait = (seconds) => new Promise(resolve => setTimeout(resolve, seconds * 1000)) +let fuseStore; + +class PoolStore { + totalEth = "0" + totalToken = "0" + tvl = "0" + amount = "0" + apr = "0" + walletBalance = "0" + footerIsOpen = false + action = "Deposit" + txInProgress = false + hash = null + val = "" + err = "" + success = "" + inputIsValid = null + inputErrMsg = "" + asset = "" + decimals = null + allowanceInProgress = null + allowance = null + userShareInUsd = "0" + collaterals = [] + collateralRatio = null + usdRatio = null + reward = null + + get collPercnet(){ + return this.collateralRatio ? (parseFloat(this.collateralRatio) * 100).toFixed(2) : "0.00" + } + + get usdPercnet(){ + return this.usdRatio ? (parseFloat(this.usdRatio) * 100).toFixed(2) : "0.00" + } + + get inputIsInvalid() { + return this.inputIsValid === false ? true : undefined; + } + + get hasAllowance() { + if(!this.allowance) return false + return toBN(this.allowance).gte(reallyLargeAllowance) + } + + get withdrawValues() { + if(this.inputIsValid && parseFloat(this.val) > 0 ){ + return { + usd: (parseFloat(this.val) * parseFloat(this.usdRatio)).toString(), + coll: (parseFloat(this.val) * parseFloat(this.collateralRatio)).toString() + } + } else { + return { + usd: "0", + coll: "0" + } + } + } + + openFooter = (action) => { + this.action = action + this.footerIsOpen = true + } + + closeFooter = () => { + this.footerIsOpen = false + } + + validateInput = (input) => { + if(isNaN(input) || parseFloat(input) <= 0){ + this.inputIsValid = false + this.inputErrMsg = `${this.action} amount must be positive` + return + } + + if(this.action === "Deposit") { + if(parseFloat(input) > parseFloat(this.walletBalance)){ + this.inputIsValid = false + this.inputErrMsg = "Insufficient wallet balance" + return + } + + if(!this.hasAllowance){ + this.inputIsValid = false + this.inputErrMsg = "Insufficient allowance, unlock to grant allowance" + return + } + } + + if(this.action === "Withdraw") { + if(parseFloat(input) > parseFloat(this.userShareInUsd)){ + this.inputIsValid = false + this.inputErrMsg = `${this.action} amount is greater than balance` + return + } + } + + this.inputIsValid = true + this.inputErrMsg = "" + return + } + + onInputChange = e => { + this.val = e.target.value; + this.validateInput(this.val) + } + + onHash = txHash => { + this.hash = txHash + } + + reset = () => { + this.txInProgress = false + this.success = "" + this.err = "" + this.hash = null + this.val = 0 + this.footerIsOpen = false + } + + grantAllowance = async (e) => { + try{ + e.preventDefault() + runInAction(()=> { + this.allowanceInProgress = true + }) + const {web3, user} = userStore + const context = this.getContext() + const tx = Interface.grantAllowance(context) + await ApiAction(tx, user, web3, 0, ()=>{}) + await this.fetchData() + this.validateInput(this.val) + } catch(err) { + console.error(err) + } finally { + this.allowanceInProgress = false + } + } + + deposit = async amount => { + try{ + if(!this.inputIsValid){ + return + } + runInAction(()=> { + this.txInProgress = true + }) + const {web3, user} = userStore + const context = this.getContext() + const tx = Interface.deposit(context, amount) + let sendETH = 0 + if (Interface.isETH(context.tokenAddress)) { + sendETH = Interface.denormlize(amount, this.decimals) + } + await ApiAction(tx, user, web3, sendETH, this.onHash) + runInAction(()=> { + this.success = true + }) + }catch (err) { + console.error(err) + runInAction(()=> { + this.err = err + }) + }finally{ + const [updateUi,] = await Promise.all([ + this.fetchData(true), + wait(5) + ]) + updateUi() + if(fuseStore){ + fuseStore.refreshStores(this.config.poolAddress) + } + this.reset() + } + } + + withdraw = async amount => { + try{ + if(!this.inputIsValid){ + return + } + runInAction(()=> { + this.txInProgress = true + }) + const {web3, user} = userStore + const context = this.getContext() + const amountInShare = await Interface.usdToShare(context, amount) + const tx = Interface.withdraw(context, amountInShare) + await ApiAction(tx, user, web3, 0, this.onHash) + runInAction(()=> { + this.success = true + }) + }catch (err) { + console.error(err) + runInAction(()=> { + this.err = err + }) + }finally{ + const [updateUi,] = await Promise.all([ + this.fetchData(true), + wait(5) + ]) + updateUi() + if(fuseStore){ + fuseStore.refreshStores(this.config.poolAddress) + } + this.reset() + } + } + + claimReward = async () => { + try{ + runInAction(()=> { + this.txInProgress = true + }) + const {web3, user} = userStore + const amountInShare = "0" + const context = this.getContext() + const tx = Interface.withdraw(context, amountInShare) + await ApiAction(tx, user, web3, 0, this.onHash) + runInAction(()=> { + this.success = true + }) + }catch (err) { + console.error(err) + runInAction(()=> { + this.err = err + }) + }finally{ + const [updateUi,] = await Promise.all([ + this.fetchData(true), + wait(5) + ]) + updateUi() + if(fuseStore){ + fuseStore.refreshStores(this.config.poolAddress) + } + this.reset() + } + } + + constructor(config) { + this.config = config + this.asset = config.tokenName + makeAutoObservable(this) + } + + init = () => { + return this.fetchData() + } + + getContext = () => { + const {web3, user, chain} = userStore + return { + web3, user, chain, ...this.config + } + } + + fetchData = async (updateFn) => { + try{ + const context = this.getContext() + this.decimals = this.config.decimals + const aprPromise = Interface.getApr(context) + .catch(err => console.error(`failed to fetch APR: ${err.message} @ ${err.stack}`)) // will not block + + const tvlPromise = Interface.getTvl(context) + const walletBalancePromise = Interface.getWalletBallance(context) + const allowancePromise = Interface.getAllowance(context) + const userShareInUsdPromise = Interface.getUserShareInUsd(context) + const collateralsPromise = Interface.getCollaterals(context) + const rewardPromise = Interface.getReward(context) + // fetching in parallel + const [walletBalance, {tvl, usdRatio, collRatio}, allowance, userShareInUsd, collaterals, reward, apr] = await Promise.all([ + walletBalancePromise, + tvlPromise, + allowancePromise, + userShareInUsdPromise, + collateralsPromise, + rewardPromise, + aprPromise + ]) + + const uiUpdate = () => { + runInAction(()=> { + this.walletBalance = stringToFixed(Interface.normlize(walletBalance, this.decimals), 5) + this.tvl = Interface.normlize(tvl, this.decimals) + this.allowance = allowance + this.userShareInUsd = stringToFixed(Interface.normlize(userShareInUsd, this.decimals), 5) + this.collateralRatio = collRatio + this.usdRatio = usdRatio + this.collaterals.replace(collaterals) + this.reward = reward + this.apr = apr + }) + } + + if (updateFn === true){ + return uiUpdate + } + uiUpdate() + }catch (err) { + console.error(`fetchData: ${err.message} @: ${err.stack}`) + } + } + +} + +class FuseStore { + stabilityPools = [] + loading = false + + constructor() { + makeAutoObservable(this) + } + + refreshStores = async (excludedPoolAddress) => { + for (const pool of this.stabilityPools){ + if(pool.config && pool.config.poolAddress === excludedPoolAddress) { + continue + } + await pool.fetchData() + } + } + + onUserConnect = async () => { + this.loading = true + const {chain} = userStore + const pools = [] + for (const pool of getPools(chain)){ + const store = new PoolStore(pool) + await store.init() + pools.push(store) + } + runInAction(()=> { + this.stabilityPools.replace(pools) + this.loading = false + }) + } +} + +fuseStore = new FuseStore() + +export default fuseStore \ No newline at end of file diff --git a/src/stores/user.store.js b/src/stores/user.store.js index f0465a1..3fadaf5 100644 --- a/src/stores/user.store.js +++ b/src/stores/user.store.js @@ -5,6 +5,7 @@ import React from "react"; import { runInAction, makeAutoObservable } from "mobx" import EventBus from "../lib/EventBus" import vestaStore from "./vesta.store" +import fuseStore from "./fuse.store" import {walletTypes, getMetaMask, getWalletConnect} from "../wallets/Wallets" const chainIdMap = { @@ -130,6 +131,7 @@ class UserStore { } this.networkType = networkType this.user = user + fuseStore.onUserConnect() vestaStore.onUserConnect() runInAction(()=> { this.loggedIn = true