From e838fda0b25d87eb043131815f23bcddf50f90f0 Mon Sep 17 00:00:00 2001 From: shmuel Date: Thu, 28 Apr 2022 16:08:02 +0300 Subject: [PATCH 01/12] WIP demo --- src/assets/coin-icons/Rari.png | Bin 0 -> 59011 bytes src/components/stability-pool/Logo.js | 2 +- src/components/stability-pool/SpActionBox.js | 5 +- .../style-components/TooltipIcon.js | 2 +- src/containers/Vesta.js | 22 +- src/lib/ApiHelper.js | 1 + src/lib/fuse/abi.js | 567 ++++++++++++++++++ src/lib/fuse/config.js | 25 + src/lib/fuse/interface.js | 361 +++++++++++ src/lib/vesta/config.js | 9 +- src/stores/fuse.store.js | 391 ++++++++++++ src/stores/user.store.js | 5 +- 12 files changed, 1361 insertions(+), 29 deletions(-) create mode 100644 src/assets/coin-icons/Rari.png create mode 100644 src/lib/fuse/abi.js create mode 100644 src/lib/fuse/config.js create mode 100644 src/lib/fuse/interface.js create mode 100644 src/stores/fuse.store.js diff --git a/src/assets/coin-icons/Rari.png b/src/assets/coin-icons/Rari.png new file mode 100644 index 0000000000000000000000000000000000000000..5f94d8458d36207d593b3984be61701ec46350e1 GIT binary patch literal 59011 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 - + diff --git a/src/components/stability-pool/SpActionBox.js b/src/components/stability-pool/SpActionBox.js index 0f85467..8dc7186 100644 --- a/src/components/stability-pool/SpActionBox.js +++ b/src/components/stability-pool/SpActionBox.js @@ -93,12 +93,15 @@ 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 {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) return (
closeFooter()}/> @@ -124,7 +127,7 @@ const SpFooterContent = observer((props) => { disabled={inputIsInvalid} onClick={()=> doAction(val)}>{action}} - {action == "Deposit" && } + {allowanceNeeded && }
{action == "Deposit" &&
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..ac58053 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/ApiHelper.js b/src/lib/ApiHelper.js index b9c91b2..c78a4e0 100644 --- a/src/lib/ApiHelper.js +++ b/src/lib/ApiHelper.js @@ -7,6 +7,7 @@ function increaseABit(number) { } function validateTx(tx) { + debugger tx.arguments.forEach(arg => { if(!arg || arg === "0x0000000000000000000000000000000000000000"){ const msg = "one of the TX arguments is falsy or invalid and might send ETH to an invalid account" diff --git a/src/lib/fuse/abi.js b/src/lib/fuse/abi.js new file mode 100644 index 0000000..139b05f --- /dev/null +++ b/src/lib/fuse/abi.js @@ -0,0 +1,567 @@ +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" + } + ], + "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..384c4d2 --- /dev/null +++ b/src/lib/fuse/config.js @@ -0,0 +1,25 @@ +// TODO add support for platform name, link, docs, + +const poolsByChain = { + + "Arbitrum Testnet": [], + "Arbitrum One": [ + { + poolAddress: "0x51fBf83818e4Fa195fD5D395a63fCfB5C45d9565", + tokenAddress: "0x0000000000000000000000000000000000000000", + tokenName: "ETH", + collateralName: "Rari", + platformName: "Pickle Fuse Rari Something", + decimals: 18, + lensAddress: "0x539a3f6d1F33C77c83e9b159e23E99FD8C26e7D9", + 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..874577e --- /dev/null +++ b/src/lib/fuse/interface.js @@ -0,0 +1,361 @@ +import Web3 from "web3" +import { abi } from "./abi" +import axios from "axios" +const {toBN, BN} = Web3.utils + +const maxAllowance = new BN("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16) +export const isETH = (tokenAddress) => tokenAddress === "0x0000000000000000000000000000000000000000" + + +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}) => { + debugger + 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) => { + debugger + 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}) => { + debugger + 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, poolAddress, tokenAddress } = context + const { Contract } = web3.eth + // const bamm = new Contract(abi.bamm, poolAddress) + + const [{amount: tokenValue}, {succ: success, value: collateralValue}] = await Promise.all([ + getUserInfo(context), + {succ: true, value: 0} // TODO: calc collateral value + ]) + + 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 getUserShareAndTotalSupply = async(web3, userAddress, poolAddress) => { + throw new Error(`function not yet implemented`) + + const { Contract } = web3.eth + const bamm = new Contract(abi.bamm, poolAddress) + const userSharePromise = bamm.methods.balanceOf(userAddress).call() + const totalSupplyPromise = bamm.methods.totalSupply().call() + + const [userShare, totalSupply] = await Promise.all([ + userSharePromise, + totalSupplyPromise + ]) + return {userShare, totalSupply} +} + +export const usdToShare = async (context, amount) => { + throw new Error(`function not yet implemented`) + + const {web3, poolAddress, tokenAddress, decimals} = context + // amount * totalSupply / TVL + const { Contract } = web3.eth + const bamm = new Contract(abi.bamm, poolAddress) + const totalSupplyPromise = bamm.methods.totalSupply().call() + const tvlPromise = getTvl(context) + const [{tvl}, totalSupply] = await Promise.all([tvlPromise, totalSupplyPromise]) + const share = (toBN(denormlize(amount, decimals)).mul(toBN(totalSupply))).div(toBN(tvl)) + 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) => { + return "0" // TODO + const {web3, user, poolAddress} = context + // tvl * userShare / totalSupply + const tvlPromise = getTvl(context) + const sharePromise = getUserShareAndTotalSupply(web3, user, poolAddress) + const [{tvl}, {userShare, totalSupply}] = await Promise.all([tvlPromise, sharePromise]) + + let usdVal; + if(totalSupply == "0"){ + usdVal = "0" + } else { + usdVal = (toBN(tvl).mul(toBN(userShare))).div(toBN(totalSupply)).toString() + } + + return usdVal +} + +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 [] // TODO: + 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) => { + debugger + const {web3, wrapper} = context + const { Contract } = web3.eth + const bammWrapper = new Contract(abi.wrapper, wrapper) + + return bammWrapper.methods.withdraw("0") +} + +export const getApr = async ({poolAddress: bammAddress, tokenAddress: vstTokenAddress, web3}) => { + return '7.7' + throw new Error(`function not yet implemented`) + + // get vesta price + const { Contract } = web3.eth + const response = await axios.get("https://api.coingecko.com/api/v3/simple/price?ids=vesta-finance&vs_currencies=USD") + const vestaPrice = Number(response.data["vesta-finance"]["usd"]) + + const bammContract = new Contract(abi.bamm, bammAddress) + + const stabilityPoolAddress = await bammContract.methods.SP().call() + const stabilityPoolContract = new Contract(abi.stabilityPool, stabilityPoolAddress) + + const communityIssuanceAddress = await stabilityPoolContract.methods.communityIssuance().call() + const communityIssuanceContract = new Contract(abi.communityIssuance, communityIssuanceAddress) + + const vestaPerMinute = Number(web3.utils.fromWei(await communityIssuanceContract.methods.vstaDistributionsByPool(stabilityPoolAddress).call())) + const minutesPerYear = 365 * 24 * 60 + const vestaPerYearInUSD = vestaPerMinute * minutesPerYear * vestaPrice + + const vstContract = new Contract(abi.erc20, vstTokenAddress) + const balanceOfSp = Number(web3.utils.fromWei(await vstContract.methods.balanceOf(stabilityPoolAddress).call())) + + //console.log({vestaPerYearInUSD}, {balanceOfSp}, {vestaPrice}, {minutesPerYear}, {vestaPerMinute}) + + const apr = vestaPerYearInUSD * 100 / balanceOfSp + + console.log(bammAddress, {apr}) + + return apr +} \ No newline at end of file diff --git a/src/lib/vesta/config.js b/src/lib/vesta/config.js index 0e06f00..c175e23 100644 --- a/src/lib/vesta/config.js +++ b/src/lib/vesta/config.js @@ -1,14 +1,7 @@ // 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/stores/fuse.store.js b/src/stores/fuse.store.js new file mode 100644 index 0000000..62f34f9 --- /dev/null +++ b/src/stores/fuse.store.js @@ -0,0 +1,391 @@ +/** + * @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 + debugger + if (Interface.isETH(context.tokenAddress)) { + sendETH = Interface.denormlize(amount, this.decimals) + } + debugger + 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).catch(err =>{ + debugger + console.error("==== err:") + console.error(err) + }) + const walletBalancePromise = Interface.getWalletBallance(context).catch(err =>{ + debugger + console.error("==== err:") + console.error(err) + }) + const allowancePromise = Interface.getAllowance(context).catch(err =>{ + debugger + console.error("==== err:") + console.error(err) + }) + const userShareInUsdPromise = Interface.getUserShareInUsd(context).catch(err =>{ + debugger + console.error("==== err:") + console.error(err) + }) + const collateralsPromise = Interface.getCollaterals(context).catch(err =>{ + debugger + console.error("==== err:") + console.error(err) + }) + const rewardPromise = Interface.getReward(context).catch(err =>{ + debugger + console.error("==== err:") + console.error(err) + }) + // 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) + debugger + 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..8717953 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,7 +131,9 @@ class UserStore { } this.networkType = networkType this.user = user - vestaStore.onUserConnect() + fuseStore.onUserConnect() + // TODO: connect vesta + //vestaStore.onUserConnect() runInAction(()=> { this.loggedIn = true this.displayConnect = false From 62b0b5e5145e7d0d959c8f5d768b52721e68f4c8 Mon Sep 17 00:00:00 2001 From: shmuel Date: Thu, 28 Apr 2022 16:08:06 +0300 Subject: [PATCH 02/12] 1.0.48 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b2afd3..b72d067 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bprotocol-react-client", - "version": "1.0.47", + "version": "1.0.48", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index dea04bf..17b8586 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bprotocol-react-client", - "version": "1.0.47", + "version": "1.0.48", "private": true, "dependencies": { "@cloudflare/kv-asset-handler": "^0.1.0", From 3d046ef4ceee4c77e66ceaacac28686e19f6351c Mon Sep 17 00:00:00 2001 From: shmuel Date: Thu, 28 Apr 2022 16:14:48 +0300 Subject: [PATCH 03/12] wip --- src/components/stability-pool/SpActionBox.js | 5 +++-- src/lib/fuse/config.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/stability-pool/SpActionBox.js b/src/components/stability-pool/SpActionBox.js index 8dc7186..345e254 100644 --- a/src/components/stability-pool/SpActionBox.js +++ b/src/components/stability-pool/SpActionBox.js @@ -290,7 +290,8 @@ 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() return (
@@ -302,7 +303,7 @@ class SpActionBox extends Component { {asset} - {collateralName && {collateralName} stability pool} + {description && {description}} {onMobile &&
} diff --git a/src/lib/fuse/config.js b/src/lib/fuse/config.js index 384c4d2..f868893 100644 --- a/src/lib/fuse/config.js +++ b/src/lib/fuse/config.js @@ -9,7 +9,7 @@ const poolsByChain = { tokenAddress: "0x0000000000000000000000000000000000000000", tokenName: "ETH", collateralName: "Rari", - platformName: "Pickle Fuse Rari Something", + description: "Rari stability pool 44", decimals: 18, lensAddress: "0x539a3f6d1F33C77c83e9b159e23E99FD8C26e7D9", rewardAddress: "0x965772e0E9c84b6f359c8597C891108DcF1c5B1A", From 48d442baf136b5ced575eeb4b21346e392616d29 Mon Sep 17 00:00:00 2001 From: shmuel Date: Thu, 28 Apr 2022 16:14:50 +0300 Subject: [PATCH 04/12] 1.0.49 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b72d067..080a47d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bprotocol-react-client", - "version": "1.0.48", + "version": "1.0.49", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 17b8586..7743945 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bprotocol-react-client", - "version": "1.0.48", + "version": "1.0.49", "private": true, "dependencies": { "@cloudflare/kv-asset-handler": "^0.1.0", From 40b4f9995f9f84a5747f165f04275b3b37155586 Mon Sep 17 00:00:00 2001 From: shmuel Date: Mon, 2 May 2022 14:10:17 +0300 Subject: [PATCH 05/12] bugFix --- src/components/style-components/AnimateNumericalString.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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))}} ) } From ab3a85c50bdb728eaf3790e8f0812dc5ea8abd90 Mon Sep 17 00:00:00 2001 From: shmuel Date: Mon, 2 May 2022 14:11:19 +0300 Subject: [PATCH 06/12] display 3 APY's in backwords compatible way --- src/components/stability-pool/SpActionBox.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/stability-pool/SpActionBox.js b/src/components/stability-pool/SpActionBox.js index 345e254..612c186 100644 --- a/src/components/stability-pool/SpActionBox.js +++ b/src/components/stability-pool/SpActionBox.js @@ -293,6 +293,15 @@ class SpActionBox extends Component { 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) + } return (
@@ -310,14 +319,14 @@ class SpActionBox extends Component { -
$
+
$
Balance
-
%
-
APR
+
%
+
APR
From 0fcc2febdbde33b6294bcad5b44f6fb9fd36e70c Mon Sep 17 00:00:00 2001 From: shmuel Date: Mon, 2 May 2022 14:11:31 +0300 Subject: [PATCH 07/12] cleanUp --- src/lib/ApiHelper.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/ApiHelper.js b/src/lib/ApiHelper.js index c78a4e0..b9c91b2 100644 --- a/src/lib/ApiHelper.js +++ b/src/lib/ApiHelper.js @@ -7,7 +7,6 @@ function increaseABit(number) { } function validateTx(tx) { - debugger tx.arguments.forEach(arg => { if(!arg || arg === "0x0000000000000000000000000000000000000000"){ const msg = "one of the TX arguments is falsy or invalid and might send ETH to an invalid account" From 6176d22752aed6dbb9c8f425724fded1814dc47a Mon Sep 17 00:00:00 2001 From: shmuel Date: Mon, 2 May 2022 14:12:03 +0300 Subject: [PATCH 08/12] abis & config --- src/lib/fuse/abi.js | 2 ++ src/lib/fuse/config.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/fuse/abi.js b/src/lib/fuse/abi.js index 139b05f..9e0733f 100644 --- a/src/lib/fuse/abi.js +++ b/src/lib/fuse/abi.js @@ -562,6 +562,8 @@ export const abi = { "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 index f868893..3306859 100644 --- a/src/lib/fuse/config.js +++ b/src/lib/fuse/config.js @@ -11,7 +11,7 @@ const poolsByChain = { collateralName: "Rari", description: "Rari stability pool 44", decimals: 18, - lensAddress: "0x539a3f6d1F33C77c83e9b159e23E99FD8C26e7D9", + bammAddress: "0x94fd843E77fe67A18d52E0AD0C9713C5a9399ef4", rewardAddress: "0x965772e0E9c84b6f359c8597C891108DcF1c5B1A", wrapperAddress: "0xEb6276Fd4D8B05104AeF4246d84D7840CB964cC8", masterChefAddress: "0x7Ecc7163469F37b777d7B8F45A667314030ACe24", From 3530bf4f7da5daf102d8aba7055ac2efc80d5257 Mon Sep 17 00:00:00 2001 From: shmuel Date: Mon, 2 May 2022 14:13:42 +0300 Subject: [PATCH 09/12] new web3 Interface for rari --- src/lib/fuse/interface.js | 149 +++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 74 deletions(-) diff --git a/src/lib/fuse/interface.js b/src/lib/fuse/interface.js index 874577e..dd584be 100644 --- a/src/lib/fuse/interface.js +++ b/src/lib/fuse/interface.js @@ -1,11 +1,11 @@ import Web3 from "web3" import { abi } from "./abi" import axios from "axios" -const {toBN, BN} = Web3.utils +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 @@ -86,7 +86,6 @@ export const getDecimals = ({web3, tokenAddress}) => { } export const getAllowance = async ({web3, user, tokenAddress, poolAddress}) => { - debugger if(isETH(tokenAddress)){ return maxAllowance.toString() } @@ -115,7 +114,6 @@ export const getWalletBallance = async ({web3, user, tokenAddress}) => { } export const deposit = (context, amount) => { - debugger const {web3, wrapperAddress, decimals, tokenAddress} = context if(isETH(tokenAddress)){ return depositEth(context) @@ -127,7 +125,6 @@ export const deposit = (context, amount) => { } const depositEth = ({web3, wrapperAddress}) => { - debugger const { Contract } = web3.eth const bammWrapper = new Contract(abi.wrapper, wrapperAddress) return bammWrapper.methods.deposit() @@ -160,13 +157,13 @@ const getUserInfo = async (context) => { export const getTvl = async(context) => { try{ - const { web3, poolAddress, tokenAddress } = context + const { web3, bammAddress, tokenAddress } = context const { Contract } = web3.eth - // const bamm = new Contract(abi.bamm, poolAddress) + const bamm = new Contract(abi.bamm, bammAddress) const [{amount: tokenValue}, {succ: success, value: collateralValue}] = await Promise.all([ getUserInfo(context), - {succ: true, value: 0} // TODO: calc collateral value + bamm.methods.getCollateralValue().call() ]) if(!success){ @@ -192,32 +189,45 @@ export const getTvl = async(context) => { } } -const getUserShareAndTotalSupply = async(web3, userAddress, poolAddress) => { - throw new Error(`function not yet implemented`) - - const { Contract } = web3.eth - const bamm = new Contract(abi.bamm, poolAddress) - const userSharePromise = bamm.methods.balanceOf(userAddress).call() - const totalSupplyPromise = bamm.methods.totalSupply().call() +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 [userShare, totalSupply] = await Promise.all([ - userSharePromise, - totalSupplyPromise - ]) - return {userShare, totalSupply} + const APY = ((((blockIntrest * blocksPerDay + 1) ** daysPerYear - 1))) * 100 + return APY.toString() } -export const usdToShare = async (context, amount) => { - throw new Error(`function not yet implemented`) - - const {web3, poolAddress, tokenAddress, decimals} = context - // amount * totalSupply / TVL +const getUserShareInEth = async(context, share) => { + const {web3, userAddress, bammAddress, masterChefAddress, wrapperAddress} = context const { Contract } = web3.eth - const bamm = new Contract(abi.bamm, poolAddress) - const totalSupplyPromise = bamm.methods.totalSupply().call() - const tvlPromise = getTvl(context) - const [{tvl}, totalSupply] = await Promise.all([tvlPromise, totalSupplyPromise]) - const share = (toBN(denormlize(amount, decimals)).mul(toBN(totalSupply))).div(toBN(tvl)) + 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() } @@ -229,21 +239,9 @@ export const withdraw = ({web3, wrapperAddress}, amountInShares) => { } export const getUserShareInUsd = async(context) => { - return "0" // TODO - const {web3, user, poolAddress} = context - // tvl * userShare / totalSupply - const tvlPromise = getTvl(context) - const sharePromise = getUserShareAndTotalSupply(web3, user, poolAddress) - const [{tvl}, {userShare, totalSupply}] = await Promise.all([tvlPromise, sharePromise]) - - let usdVal; - if(totalSupply == "0"){ - usdVal = "0" - } else { - usdVal = (toBN(tvl).mul(toBN(userShare))).div(toBN(totalSupply)).toString() - } - - return usdVal + const {amount: bammShare} = await getUserInfo(context) + const usdVal = await getUserShareInEth(context, bammShare) + return usdVal.toString() } export const getSymbol = (web3, tokenAddress) => { @@ -319,7 +317,6 @@ export const getReward = async(context) => { } export const claimReward = async (context) => { - debugger const {web3, wrapper} = context const { Contract } = web3.eth const bammWrapper = new Contract(abi.wrapper, wrapper) @@ -327,35 +324,39 @@ export const claimReward = async (context) => { return bammWrapper.methods.withdraw("0") } -export const getApr = async ({poolAddress: bammAddress, tokenAddress: vstTokenAddress, web3}) => { - return '7.7' - throw new Error(`function not yet implemented`) - - // get vesta price +export const getApr = async (context) => { + const {web3, wrapperAddress, bammAddress, masterChefAddress, masterChefPID} = context const { Contract } = web3.eth - const response = await axios.get("https://api.coingecko.com/api/v3/simple/price?ids=vesta-finance&vs_currencies=USD") - const vestaPrice = Number(response.data["vesta-finance"]["usd"]) - const bammContract = new Contract(abi.bamm, bammAddress) + 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 stabilityPoolAddress = await bammContract.methods.SP().call() - const stabilityPoolContract = new Contract(abi.stabilityPool, stabilityPoolAddress) - - const communityIssuanceAddress = await stabilityPoolContract.methods.communityIssuance().call() - const communityIssuanceContract = new Contract(abi.communityIssuance, communityIssuanceAddress) - - const vestaPerMinute = Number(web3.utils.fromWei(await communityIssuanceContract.methods.vstaDistributionsByPool(stabilityPoolAddress).call())) - const minutesPerYear = 365 * 24 * 60 - const vestaPerYearInUSD = vestaPerMinute * minutesPerYear * vestaPrice - - const vstContract = new Contract(abi.erc20, vstTokenAddress) - const balanceOfSp = Number(web3.utils.fromWei(await vstContract.methods.balanceOf(stabilityPoolAddress).call())) - - //console.log({vestaPerYearInUSD}, {balanceOfSp}, {vestaPrice}, {minutesPerYear}, {vestaPerMinute}) - - const apr = vestaPerYearInUSD * 100 / balanceOfSp - - console.log(bammAddress, {apr}) - - return apr + 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 From 92b9566654a097d68cd5a1773984318d0a483415 Mon Sep 17 00:00:00 2001 From: shmuel Date: Mon, 2 May 2022 14:14:09 +0300 Subject: [PATCH 10/12] fuse.store --- src/stores/fuse.store.js | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/src/stores/fuse.store.js b/src/stores/fuse.store.js index 62f34f9..6a17f5e 100644 --- a/src/stores/fuse.store.js +++ b/src/stores/fuse.store.js @@ -170,11 +170,9 @@ class PoolStore { const context = this.getContext() const tx = Interface.deposit(context, amount) let sendETH = 0 - debugger if (Interface.isETH(context.tokenAddress)) { sendETH = Interface.denormlize(amount, this.decimals) } - debugger await ApiAction(tx, user, web3, sendETH, this.onHash) runInAction(()=> { this.success = true @@ -286,36 +284,12 @@ class PoolStore { 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).catch(err =>{ - debugger - console.error("==== err:") - console.error(err) - }) - const walletBalancePromise = Interface.getWalletBallance(context).catch(err =>{ - debugger - console.error("==== err:") - console.error(err) - }) - const allowancePromise = Interface.getAllowance(context).catch(err =>{ - debugger - console.error("==== err:") - console.error(err) - }) - const userShareInUsdPromise = Interface.getUserShareInUsd(context).catch(err =>{ - debugger - console.error("==== err:") - console.error(err) - }) - const collateralsPromise = Interface.getCollaterals(context).catch(err =>{ - debugger - console.error("==== err:") - console.error(err) - }) - const rewardPromise = Interface.getReward(context).catch(err =>{ - debugger - console.error("==== err:") - console.error(err) - }) + 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, @@ -330,7 +304,6 @@ class PoolStore { const uiUpdate = () => { runInAction(()=> { this.walletBalance = stringToFixed(Interface.normlize(walletBalance, this.decimals), 5) - debugger this.tvl = Interface.normlize(tvl, this.decimals) this.allowance = allowance this.userShareInUsd = stringToFixed(Interface.normlize(userShareInUsd, this.decimals), 5) From 58850669997a94799491a7bdeff579ade5bcacb5 Mon Sep 17 00:00:00 2001 From: shmuel Date: Mon, 2 May 2022 14:24:31 +0300 Subject: [PATCH 11/12] cleanUp todo's + displaying vesta --- src/components/stability-pool/View.js | 1 - src/containers/Vesta.js | 2 +- src/lib/fuse/config.js | 1 - src/lib/fuse/interface.js | 2 +- src/lib/vesta/config.js | 2 -- src/lib/vesta/interface.js | 1 - src/stores/user.store.js | 3 +-- 7 files changed, 3 insertions(+), 9 deletions(-) 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/containers/Vesta.js b/src/containers/Vesta.js index ac58053..c1753c5 100644 --- a/src/containers/Vesta.js +++ b/src/containers/Vesta.js @@ -32,7 +32,7 @@ class Vesta extends Component { loading...
} {!loading && fuseStore.stabilityPools.map((sp, i)=> )} - {/* {!loading && vestaStore.stabilityPools.map((sp, i)=> )} */} + {!loading && vestaStore.stabilityPools.map((sp, i)=> )}
} {!hideInfoPage && } diff --git a/src/lib/fuse/config.js b/src/lib/fuse/config.js index 3306859..431e61a 100644 --- a/src/lib/fuse/config.js +++ b/src/lib/fuse/config.js @@ -1,4 +1,3 @@ -// TODO add support for platform name, link, docs, const poolsByChain = { diff --git a/src/lib/fuse/interface.js b/src/lib/fuse/interface.js index dd584be..55b8542 100644 --- a/src/lib/fuse/interface.js +++ b/src/lib/fuse/interface.js @@ -278,7 +278,7 @@ export const getAssetDistrobution = async({web3, poolAddress, user}, assetAddres } export const getCollaterals = async(context) => { - return [] // TODO: + return [] const { web3, poolAddress } = context const { Contract } = web3.eth const bamm = new Contract(abi.bamm, poolAddress) diff --git a/src/lib/vesta/config.js b/src/lib/vesta/config.js index c175e23..313ea99 100644 --- a/src/lib/vesta/config.js +++ b/src/lib/vesta/config.js @@ -1,5 +1,3 @@ -// TODO add support for platform name, link, docs, - const poolsByChain = { "Arbitrum Testnet": [ 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/user.store.js b/src/stores/user.store.js index 8717953..3fadaf5 100644 --- a/src/stores/user.store.js +++ b/src/stores/user.store.js @@ -132,8 +132,7 @@ class UserStore { this.networkType = networkType this.user = user fuseStore.onUserConnect() - // TODO: connect vesta - //vestaStore.onUserConnect() + vestaStore.onUserConnect() runInAction(()=> { this.loggedIn = true this.displayConnect = false From 22bdd5b171c69c5baacf2bc3cebc533b16b9774c Mon Sep 17 00:00:00 2001 From: shmuel Date: Mon, 2 May 2022 15:17:13 +0300 Subject: [PATCH 12/12] adding a prefix & suffix for the denominator for $ sign or token symbol --- src/components/stability-pool/SpActionBox.js | 16 +++++++++++----- src/lib/fuse/config.js | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/components/stability-pool/SpActionBox.js b/src/components/stability-pool/SpActionBox.js index 612c186..edcc671 100644 --- a/src/components/stability-pool/SpActionBox.js +++ b/src/components/stability-pool/SpActionBox.js @@ -96,12 +96,15 @@ 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()}/> @@ -141,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}

}
} @@ -302,6 +305,9 @@ class SpActionBox extends Component { 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 (
@@ -319,7 +325,7 @@ class SpActionBox extends Component { -
$
+
{prefix} {suffix}
Balance
diff --git a/src/lib/fuse/config.js b/src/lib/fuse/config.js index 431e61a..b556a6a 100644 --- a/src/lib/fuse/config.js +++ b/src/lib/fuse/config.js @@ -6,6 +6,7 @@ const poolsByChain = { { poolAddress: "0x51fBf83818e4Fa195fD5D395a63fCfB5C45d9565", tokenAddress: "0x0000000000000000000000000000000000000000", + denominator: "ETH", tokenName: "ETH", collateralName: "Rari", description: "Rari stability pool 44",