Search
Search

Transaction: 8aejfuA...9QTv

Receiver
Status
Succeeded
Transaction Fee
0.00112 
Deposit Value
0 
Gas Used
11 Tgas
Attached Gas
100 Tgas
Created
November 05, 2023 at 2:38:03pm
Hash
8aejfuAWiB4c7X4RkqZaHfHyWk86maw3vWKQwf8X9QTv

Actions

Called method: 'set' in contract: social.near
Arguments:
{ "data": { "deepcryptodive.near": { "widget": { "SPARK-local": { "": "// Original code on which this is based can be found at https://near.org/near/widget/ComponentDetailsPage?src=bluebiu.near/widget/ZKEVM.AAVE\nconst ROUND_DOWN = 0;\nconst CONTRACT_ABI = {\n wrappedTokenGatewayV3ABI:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/WrappedTokenGatewayV3ABI.json\",\n erc20Abi:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/ERC20Permit.json\",\n aavePoolV3ABI:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/AAVEPoolV3.json\",\n variableDebtTokenABI:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/VariableDebtToken.json\",\n walletBalanceProviderABI:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/WalletBalanceProvider.json\",\n};\nconst DEFAULT_CHAIN_ID = 100;\nconst NATIVE_SYMBOL_ADDRESS_MAP_KEY = \"0x0\";\nconst ETH_TOKEN = { name: \"Ethereum\", symbol: \"ETH\", decimals: 18 };\nconst WETH_TOKEN = { name: \"Wrapped Ether\", symbol: \"WETH\", decimals: 18 };\nconst MATIC_TOKEN = { name: \"Matic\", symbol: \"MATIC\", decimals: 18 };\nconst WMATIC_TOKEN = { name: \"Wrapped Matic\", symbol: \"WMATIC\", decimals: 18 };\nconst XDAI_TOKEN = { name: \"XDAI\", symbol: \"XDAI\", decimals: 18 };\nconst WXDAI_TOKEN = { name: \"Wrapped XDAI\", symbol: \"WXDAI\", decimals: 18 };\nconst ACTUAL_BORROW_AMOUNT_RATE = 0.99;\n\n// Get Spark Lend config by chain id\nfunction getNetworkConfig(chainId) {\n const abis = {\n wrappedTokenGatewayV3ABI: fetch(CONTRACT_ABI.wrappedTokenGatewayV3ABI),\n erc20Abi: fetch(CONTRACT_ABI.erc20Abi),\n aavePoolV3ABI: fetch(CONTRACT_ABI.aavePoolV3ABI),\n variableDebtTokenABI: fetch(CONTRACT_ABI.variableDebtTokenABI),\n walletBalanceProviderABI: fetch(CONTRACT_ABI.walletBalanceProviderABI),\n };\n\n const constants = {\n FIXED_LIQUIDATION_VALUE: \"1.0\",\n MAX_UINT_256:\n \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",\n AAVE_API_BASE_URL: \"http://localhost:8080\",\n // this connects to our custom Spark Protocol Data Service\n // see https://github.com/Deepcryptodive/spark-data-service\n // If you want to run it on localhost, change it to \"http://localhost:8080\"\n // If you want to run it online, change it to \"https://spark-api.pages.dev/\"\n };\n\n switch (chainId) {\n case 1: // ethereum mainnet\n return {\n chainName: \"Ethereum Mainnet\",\n nativeCurrency: ETH_TOKEN,\n nativeWrapCurrency: WETH_TOKEN,\n rpcUrl: \"https://eth-pokt.nodies.app\",\n aavePoolV3Address: \"0xC13e21B648A5Ee794902342038FF3aDAB66BE987\",\n wrappedTokenGatewayV3Address:\n \"0xBD7D6a9ad7865463DE44B05F04559f65e3B11704\",\n balanceProviderAddress: \"0xd2AeF86F51F92E8e49F42454c287AE4879D1BeDc\",\n ...abis,\n ...constants,\n };\n case 42161: // arbitrum one - TO BE REMOVED\n return {\n chainName: \"Arbitrum Mainnet\",\n nativeCurrency: ETH_TOKEN,\n nativeWrapCurrency: WETH_TOKEN,\n rpcUrl: \"https://arb1.arbitrum.io/rpc\",\n aavePoolV3Address: \"0x794a61358D6845594F94dc1DB02A252b5b4814aD\",\n wrappedTokenGatewayV3Address:\n \"0xB5Ee21786D28c5Ba61661550879475976B707099\",\n balanceProviderAddress: \"0xBc790382B3686abffE4be14A030A96aC6154023a\",\n ...abis,\n ...constants,\n };\n case 137: // polygon mainnet - still configured to Aave v3 for debugging!\n return {\n chainName: \"Polygon Mainnet\",\n nativeCurrency: MATIC_TOKEN,\n nativeWrapCurrency: WMATIC_TOKEN,\n rpcUrl: \"https://polygon-pokt.nodies.app\",\n aavePoolV3Address: \"0x794a61358D6845594F94dc1DB02A252b5b4814aD\",\n wrappedTokenGatewayV3Address:\n \"0x1e4b7A6b903680eab0c5dAbcb8fD429cD2a9598c\",\n balanceProviderAddress: \"0xBc790382B3686abffE4be14A030A96aC6154023a\",\n ...abis,\n ...constants,\n };\n case 100: // Gnosis\n return {\n chainName: \"Gnosis Mainnet\",\n nativeCurrency: XDAI_TOKEN,\n nativeWrapCurrency: WXDAI_TOKEN,\n rpcUrl: \"https://gnosis-pokt.nodies.app\",\n aavePoolV3Address: \"0x2Dae5307c5E3FD1CF5A72Cb6F698f915860607e0\",\n wrappedTokenGatewayV3Address:\n \"0xBD7D6a9ad7865463DE44B05F04559f65e3B11704\", // NOTE: not listed in the Spark docs - got it from Gnosisscan\n balanceProviderAddress: \"0xd2AeF86F51F92E8e49F42454c287AE4879D1BeDc\",\n ...abis,\n ...constants,\n };\n case 1442: // zkevm testnet - TO BE REMOVED\n return {\n chainName: \"Polygon zkEVM Testnet\",\n nativeCurrency: ETH_TOKEN,\n nativeWrapCurrency: WETH_TOKEN,\n rpcUrl: \"https://rpc.public.zkevm-test.net\",\n aavePoolV3Address: \"0x4412c92f6579D9FC542D108382c8D1d6D2Be63d9\",\n wrappedTokenGatewayV3Address:\n \"0xD82940E16D25aB1349914e1C369eF1b287d457BF\",\n balanceProviderAddress: \"0x0da6DCAd2bE4801b644AEE679e0AdE008bB4bc6b\",\n ...abis,\n ...constants,\n };\n default:\n throw new Error(\"unknown chain id\");\n }\n}\n\nfunction switchEthereumChain(chainId) {\n const chainIdHex = `0x${chainId.toString(16)}`;\n const res = Ethers.send(\"wallet_switchEthereumChain\", [\n { chainId: chainIdHex },\n ]);\n // If `res` === `undefined`, it means switch chain failed, which is very weird but it works.\n // If `res` is `null` the function is either not called or executed successfully.\n if (res === undefined) {\n console.log(\n `Failed to switch chain to ${chainId}. Add the chain to wallet`\n );\n const config = getNetworkConfig(chainId);\n Ethers.send(\"wallet_addEthereumChain\", [\n {\n chainId: chainIdHex,\n chainName: config.chainName,\n nativeCurrency: config.nativeCurrency,\n rpcUrls: [config.rpcUrl],\n },\n ]);\n }\n}\n\nif (\n state.chainId === undefined &&\n ethers !== undefined &&\n Ethers.send(\"eth_requestAccounts\", [])[0]\n) {\n Ethers.provider()\n .getNetwork()\n .then((data) => {\n const chainId = data?.chainId;\n const config = getNetworkConfig(chainId);\n if (!config) {\n console.log(`Unsupport chain, chainId: ${chainId}`);\n State.update({ isChainSupported: false });\n switchEthereumChain(DEFAULT_CHAIN_ID);\n } else {\n State.update({ chainId, isChainSupported: true });\n }\n });\n}\n\nfunction isValid(a) {\n if (!a) return false;\n if (isNaN(Number(a))) return false;\n if (a === \"\") return false;\n return true;\n}\n\nconst GAS_LIMIT_RECOMMENDATIONS = {\n default: {\n limit: \"210000\",\n recommended: \"210000\",\n },\n approval: {\n limit: \"65000\",\n recommended: \"65000\",\n },\n creditDelegationApproval: {\n limit: \"55000\",\n recommended: \"55000\",\n },\n supply: {\n limit: \"300000\",\n recommended: \"300000\",\n },\n deposit: {\n limit: \"300000\",\n recommended: \"300000\",\n },\n borrow: {\n limit: \"400000\",\n recommended: \"400000\",\n },\n withdraw: {\n limit: \"230000\",\n recommended: \"300000\",\n },\n liquidationCall: {\n limit: \"700000\",\n recommended: \"700000\",\n },\n liquidationFlash: {\n limit: \"995000\",\n recommended: \"995000\",\n },\n repay: {\n limit: \"300000\",\n recommended: \"300000\",\n },\n borrowETH: {\n limit: \"450000\",\n recommended: \"450000\",\n },\n withdrawETH: {\n limit: \"640000\",\n recommended: \"640000\",\n },\n swapCollateral: {\n limit: \"1000000\",\n recommended: \"1000000\",\n },\n repayCollateral: {\n limit: \"700000\",\n recommended: \"700000\",\n },\n migrateV3: {\n limit: \"700000\",\n recommended: \"700000\",\n },\n supplyWithPermit: {\n limit: \"350000\",\n recommended: \"350000\",\n },\n repayWithPermit: {\n limit: \"350000\",\n recommended: \"350000\",\n },\n vote: {\n limit: \"125000\",\n recommended: \"125000\",\n },\n stake: {\n limit: \"395000\",\n recommended: \"395000\",\n },\n claimRewards: {\n limit: \"275000\",\n recommended: \"275000\",\n },\n setUsageAsCollateral: {\n limit: \"138000\",\n recommended: \"138000\",\n },\n};\n\nfunction getGasPrice() {\n return Ethers.provider().getGasPrice();\n}\n\nfunction gasEstimation(action) {\n const assetsToSupply = state.assetsToSupply;\n if (!assetsToSupply) {\n return \"-\";\n }\n const baseAsset = assetsToSupply.find(\n (asset) => asset.symbol === config.nativeCurrency.symbol\n );\n if (!baseAsset) {\n return \"-\";\n }\n const { marketReferencePriceInUsd, decimals } = baseAsset;\n return getGasPrice().then((gasPrice) => {\n const gasLimit = GAS_LIMIT_RECOMMENDATIONS[action].limit;\n return Big(gasPrice.toString())\n .mul(gasLimit)\n .div(Big(10).pow(decimals))\n .mul(marketReferencePriceInUsd)\n .toFixed(2);\n });\n}\n\nfunction depositETHGas() {\n return gasEstimation(\"deposit\");\n}\n\nfunction depositERC20Gas() {\n return gasEstimation(\"supplyWithPermit\");\n}\n\nfunction withdrawETHGas() {\n return gasEstimation(\"withdrawETH\");\n}\n\nfunction withdrawERC20Gas() {\n return gasEstimation(\"withdraw\");\n}\n\nfunction borrowETHGas() {\n return gasEstimation(\"borrowETH\");\n}\n\nfunction borrowERC20Gas() {\n return gasEstimation(\"borrow\");\n}\n\nfunction repayETHGas() {\n return gasEstimation(\"repay\");\n}\n\nfunction repayERC20Gas() {\n return gasEstimation(\"repayWithPermit\");\n}\n\n// interface Market {\n// id: string,\n// underlyingAsset: string,\n// name: string,\n// symbol: string,\n// decimals: number,\n// supplyAPY: string;\n// marketReferencePriceInUsd: string;\n// usageAsCollateralEnabled: boolean;\n// aTokenAddress: string;\n// variableBorrowAPY: string;\n// }\n// returns Market[]\nfunction getMarkets(chainId) {\n return asyncFetch(`${config.AAVE_API_BASE_URL}/${chainId}/markets`);\n}\n\n/**\n * @param {string} account user address\n * @param {string[]} tokens list of token addresses\n */\n// interface TokenBalance {\n// token: string,\n// balance: string,\n// decimals: number,\n// }\n// returns TokenBalance[]\nfunction getUserBalances(chainId, account, tokens) {\n const url = `${\n config.AAVE_API_BASE_URL\n }/${chainId}/balances?account=${account}&tokens=${tokens.join(\"|\")}`;\n return asyncFetch(url);\n}\n\n// interface UserDeposit {\n// underlyingAsset: string,\n// name: string,\n// symbol: string,\n// scaledATokenBalance: string,\n// usageAsCollateralEnabledOnUser: boolean,\n// underlyingBalance: string,\n// underlyingBalanceUSD: string,\n// }\n// returns UserDeposit[]\nfunction getUserDeposits(chainId, address) {\n return asyncFetch(\n `${config.AAVE_API_BASE_URL}/${chainId}/deposits/${address}`\n );\n}\n\n// interface UserDebtSummary {\n// healthFactor: string,\n// netWorthUSD: string,\n// availableBorrowsUSD: string,\n// debts: UserDebt[],\n// }\n// interface UserDebt {\n// underlyingAsset: string;\n// name: string;\n// symbol: string;\n// usageAsCollateralEnabledOnUser: boolean,\n// scaledVariableDebt: string,\n// variableBorrows: string,\n// variableBorrowsUSD: string,\n// }\n// returns UserDebtSummary\nfunction getUserDebts(chainId, address) {\n return asyncFetch(`${config.AAVE_API_BASE_URL}/${chainId}/debts/${address}`);\n}\n\n// App config\nfunction getConfig(network) {\n const chainId = state.chainId;\n switch (network) {\n case \"mainnet\":\n return {\n ownerId: \"aave-v3.near\",\n nodeUrl: \"https://rpc.mainnet.near.org\",\n ipfsPrefix: \"https://ipfs.near.social/ipfs\",\n ...(chainId ? getNetworkConfig(chainId) : {}),\n };\n case \"testnet\":\n return {\n ownerId: \"aave-v3.testnet\",\n nodeUrl: \"https://rpc.testnet.near.org\",\n ipfsPrefix: \"https://ipfs.near.social/ipfs\",\n ...(chainId ? getNetworkConfig(chainId) : {}),\n };\n default:\n throw Error(`Unconfigured environment '${network}'.`);\n }\n}\nconst config = getConfig(context.networkId);\n\n// App states\nState.init({\n imports: {},\n chainId: undefined, // chainId is undefined in the case of unsupported chains\n isChainSupported: true,\n showWithdrawModal: false,\n showSupplyModal: false,\n showRepayModal: false,\n showBorrowModal: false,\n walletConnected: false,\n assetsToSupply: undefined,\n yourSupplies: undefined,\n assetsToBorrow: undefined,\n yourBorrows: undefined,\n address: undefined,\n baseAssetBalance: undefined,\n selectTab: \"supply\", // supply | borrow\n});\n\nconst loading =\n !state.assetsToSupply || !state.yourSupplies || !state.assetsToBorrow;\n\n// Import functions to state.imports\nfunction importFunctions(imports) {\n if (loading) {\n State.update({\n imports,\n });\n }\n}\n\n// Define the modules you'd like to import\nconst modules = {\n number: `${config.ownerId}/widget/Utils.Number`,\n date: `${config.ownerId}/widget/Utils.Date`,\n data: `${config.ownerId}/widget/AAVE.Data`,\n};\n// Import functions\n// const { formatAmount } = state.imports.number;\n// const { formatDateTime } = state.imports.date;\n\nfunction checkProvider() {\n const provider = Ethers.provider();\n if (provider) {\n State.update({ walletConnected: true });\n } else {\n State.update({ walletConnected: false });\n }\n}\n\nfunction calculateAvailableBorrows({\n availableBorrowsUSD,\n marketReferencePriceInUsd,\n}) {\n return isValid(availableBorrowsUSD) && isValid(marketReferencePriceInUsd)\n ? Big(availableBorrowsUSD).div(marketReferencePriceInUsd).toFixed()\n : Number(0).toFixed();\n}\n\nfunction bigMin(_a, _b) {\n const a = Big(_a);\n const b = Big(_b);\n return a.gt(b) ? b : a;\n}\n\nfunction formatHealthFactor(healthFactor) {\n if (healthFactor === \"∞\") return healthFactor;\n if (!healthFactor || !isValid(healthFactor)) return \"-\";\n if (Number(healthFactor) === -1) return \"∞\";\n return Big(healthFactor).toFixed(2, ROUND_DOWN);\n}\n\nfunction batchBalanceOf(chainId, userAddress, tokenAddresses, abi) {\n const balanceProvider = new ethers.Contract(\n config.balanceProviderAddress,\n abi.body,\n Ethers.provider().getSigner()\n );\n\n return balanceProvider.batchBalanceOf([userAddress], tokenAddresses);\n}\n\n// update data in async manner\nfunction updateData(refresh) {\n // check abi loaded\n if (\n Object.keys(CONTRACT_ABI)\n .map((key) => config[key])\n .filter((ele) => !!ele).length !== Object.keys(CONTRACT_ABI).length\n ) {\n return;\n }\n const provider = Ethers.provider();\n if (!provider) {\n return;\n }\n provider\n .getSigner()\n ?.getAddress()\n ?.then((address) => {\n State.update({ address });\n });\n provider\n .getSigner()\n ?.getBalance()\n .then((balance) => State.update({ baseAssetBalance: balance }));\n if (!state.address || !state.baseAssetBalance) {\n return;\n }\n\n getMarkets(state.chainId).then((marketsResponse) => {\n if (!marketsResponse) {\n return;\n }\n const markets = marketsResponse.body;\n const marketsMapping = markets.reduce((prev, cur) => {\n prev[cur.underlyingAsset] = cur;\n return prev;\n }, {});\n\n const nativeMarket = markets.find(\n (market) => market.symbol === config.nativeWrapCurrency.symbol\n );\n markets.push({\n ...nativeMarket,\n ...{\n ...config.nativeCurrency,\n supportPermit: true,\n },\n });\n\n // get user balances\n batchBalanceOf(\n state.chainId,\n state.address,\n markets.map((market) => market.underlyingAsset),\n config.walletBalanceProviderABI\n )\n .then((balances) => balances.map((balance) => balance.toString()))\n .then((userBalances) => {\n const assetsToSupply = markets\n .map((market, idx) => {\n const balanceRaw = Big(\n market.symbol === config.nativeCurrency.symbol\n ? state.baseAssetBalance\n : userBalances[idx]\n ).div(Big(10).pow(market.decimals));\n const balance = balanceRaw.toFixed(market.decimals, ROUND_DOWN);\n const balanceInUSD = balanceRaw\n .mul(market.marketReferencePriceInUsd)\n .toFixed(3, ROUND_DOWN);\n return {\n ...market,\n balance,\n balanceInUSD,\n };\n })\n .sort((asset1, asset2) => {\n const balanceInUSD1 = Number(asset1.balanceInUSD);\n const balanceInUSD2 = Number(asset2.balanceInUSD);\n if (balanceInUSD1 !== balanceInUSD2)\n return balanceInUSD2 - balanceInUSD1;\n return asset1.symbol.localeCompare(asset2.symbol);\n });\n\n State.update({\n assetsToSupply,\n });\n // get user borrow data\n updateUserDebts(marketsMapping, assetsToSupply, refresh);\n });\n // get user supplies\n updateUserSupplies(marketsMapping, refresh);\n });\n}\n\nfunction updateUserSupplies(marketsMapping, refresh) {\n const prevYourSupplies = state.yourSupplies;\n getUserDeposits(state.chainId, state.address).then((userDepositsResponse) => {\n if (!userDepositsResponse) {\n return;\n }\n const userDeposits = userDepositsResponse.body.filter(\n (row) => Number(row.underlyingBalance) !== 0\n );\n const yourSupplies = userDeposits.map((userDeposit) => {\n const market = marketsMapping[userDeposit.underlyingAsset];\n return {\n ...market,\n ...userDeposit,\n ...(market.symbol === config.nativeWrapCurrency.symbol\n ? {\n ...config.nativeCurrency,\n supportPermit: true,\n }\n : {}),\n };\n });\n\n State.update({\n yourSupplies,\n });\n\n if (\n refresh &&\n JSON.stringify(prevYourSupplies) === JSON.stringify(yourSupplies) &&\n yourSupplies.length !== 0\n ) {\n console.log(\"refresh supplies again ...\", prevYourSupplies, yourSupplies);\n setTimeout(updateData, 500);\n }\n });\n}\n\nfunction updateUserDebts(marketsMapping, assetsToSupply, refresh) {\n if (!marketsMapping || !assetsToSupply) {\n return;\n }\n\n const prevYourBorrows = state.yourBorrows;\n // userDebts depends on the balance from assetsToSupply\n const assetsToSupplyMap = assetsToSupply.reduce((prev, cur) => {\n if (cur.symbol !== config.nativeCurrency.symbol) {\n prev[cur.underlyingAsset] = cur;\n } else {\n prev[NATIVE_SYMBOL_ADDRESS_MAP_KEY] = cur;\n }\n return prev;\n }, {});\n\n getUserDebts(state.chainId, state.address).then((userDebtsResponse) => {\n if (!userDebtsResponse) {\n return;\n }\n const userDebts = userDebtsResponse.body;\n const assetsToBorrow = {\n ...userDebts,\n healthFactor: formatHealthFactor(userDebts.healthFactor),\n debts: userDebts.debts\n .map((userDebt) => {\n const market = marketsMapping[userDebt.underlyingAsset];\n if (!market) {\n return;\n }\n const { availableLiquidityUSD } = market;\n const availableBorrowsUSD = bigMin(\n userDebts.availableBorrowsUSD,\n availableLiquidityUSD\n )\n .times(ACTUAL_BORROW_AMOUNT_RATE)\n .toFixed();\n const assetsToSupplyMapKey =\n market.symbol === config.nativeWrapCurrency.symbol\n ? NATIVE_SYMBOL_ADDRESS_MAP_KEY\n : userDebt.underlyingAsset;\n return {\n ...market,\n ...userDebt,\n ...(market.symbol === config.nativeWrapCurrency.symbol\n ? {\n ...config.nativeCurrency,\n supportPermit: true,\n }\n : {}),\n availableBorrows: calculateAvailableBorrows({\n availableBorrowsUSD,\n marketReferencePriceInUsd: market.marketReferencePriceInUsd,\n }),\n availableBorrowsUSD,\n balance: assetsToSupplyMap[assetsToSupplyMapKey].balance,\n balanceInUSD: assetsToSupplyMap[assetsToSupplyMapKey].balanceInUSD,\n };\n })\n .filter((asset) => !!asset)\n .sort((asset1, asset2) => {\n const availableBorrowsUSD1 = Number(asset1.availableBorrowsUSD);\n const availableBorrowsUSD2 = Number(asset2.availableBorrowsUSD);\n if (availableBorrowsUSD1 !== availableBorrowsUSD2)\n return availableBorrowsUSD2 - availableBorrowsUSD1;\n return asset1.symbol.localeCompare(asset2.symbol);\n })\n .filter((asset) => {\n return asset.borrowingEnabled;\n }),\n };\n const yourBorrows = {\n ...assetsToBorrow,\n debts: assetsToBorrow.debts.filter(\n (row) =>\n !isNaN(Number(row.variableBorrowsUSD)) &&\n Number(row.variableBorrowsUSD) > 0\n ),\n };\n\n State.update({\n yourBorrows,\n assetsToBorrow,\n });\n\n if (\n refresh &&\n JSON.stringify(prevYourBorrows) === JSON.stringify(yourBorrows)\n ) {\n console.log(\"refresh borrows again ...\", prevYourBorrows, yourBorrows);\n setTimeout(updateData, 500);\n }\n });\n}\n\nfunction onActionSuccess({ msg, callback }) {\n // update data if action finishes\n updateData(true);\n // update UI after data has almost loaded\n setTimeout(() => {\n if (callback) {\n callback();\n }\n if (msg) {\n State.update({ alertModalText: msg });\n }\n }, 5000);\n}\n\ncheckProvider();\nif (state.walletConnected && state.chainId && loading) {\n updateData();\n}\n\nconst PageBackground = styled.div`\n background-color: #1e202f;\n`;\n\nconst StyledContainer = styled.div`\n color: white;\n border: 1px solid white;\n padding-top: 1rem;\n min-width: 100%;\n text-align: center;\n`;\n\nconst Body = styled.div`\n padding-top: 24px;\n min-height: 100vh;\n color: white;\n .top-title {\n display: flex;\n justify-content: space-between;\n line-height: 48px;\n }\n`;\n\nconst FlexContainer = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n flex-direction: column;\n`;\nconst TopContainer = styled.div`\n display: flex;\n justify-content: space-between;\n align-items: center;\n .tabSwitcher {\n border: 1px solid #332c4b;\n background: #222436;\n border-radius: 10px;\n }\n .networkSwitcher {\n border: 1px solid #332c4b;\n background: #222436;\n border-radius: 10px;\n padding: 8px 12px 8px 0;\n }\n`;\nconst AAVEContainer = styled.div`\n width: 100%;\n margin: 0 auto;\n padding-bottom: 50px;\n .tip {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n }\n`;\nconst TitleText = styled.div`\n font-size: 20px;\n font-weight: 700;\n margin-bottom: 32px;\n color: #ffffff;\n`;\n// Component body\nconst body = loading ? (\n <>\n <Body>\n <TitleText>SparkNexus</TitleText>\n <div className=\"load\">\n <Widget\n src={`deepcryptodive.near/widget/SPARK.Loader`}\n props={{\n walletConnected: state.walletConnected,\n isChainSupported: state.isChainSupported,\n chainId: state.chainId,\n DEFAULT_CHAIN_ID,\n getNetworkConfig,\n }}\n />\n </div>\n </Body>\n </>\n) : (\n <>\n <Body>\n <div className=\"top-title\">\n <TitleText>Spark Protocol</TitleText>\n <div className=\"tabSwitcher\">\n <Widget\n src={`guessme.near/widget/ZKEVM.AAVE.TabSwitcher`}\n props={{\n config,\n select: state.selectTab,\n setSelect: (tabName) => State.update({ selectTab: tabName }),\n }}\n />\n </div>\n </div>\n <TopContainer>\n <Widget\n src={`bluebiu.near/widget/ZKEVM.AAVE.HeroData`}\n props={{\n config,\n netWorth: `$ ${\n state.assetsToBorrow?.netWorthUSD\n ? Big(state.assetsToBorrow.netWorthUSD).toFixed(2)\n : \"-\"\n }`,\n netApy: `${\n state.assetsToBorrow?.netAPY\n ? Number(\n Big(state.assetsToBorrow.netAPY).times(100).toFixed(2)\n ) === 0\n ? \"0.00\"\n : Big(state.assetsToBorrow.netAPY).times(100).toFixed(2)\n : \"-\"\n }%`,\n healthFactor: formatHealthFactor(state.assetsToBorrow.healthFactor),\n showHealthFactor:\n state.yourBorrows &&\n state.yourBorrows.debts &&\n state.yourBorrows.debts.length > 0,\n }}\n />\n <div className=\"networkSwitcher\">\n <Widget\n src={`deepcryptodive.near/widget/SPARK.NetworkSwitcher`}\n props={{\n chainId: state.chainId,\n config,\n switchNetwork: (chainId) => {\n switchEthereumChain(chainId);\n },\n }}\n />\n </div>\n </TopContainer>\n {state.selectTab === \"supply\" && (\n <>\n <Widget\n src={`deepcryptodive.near/widget/SPARK.Card.YourSupplies`}\n props={{\n config,\n chainId: state.chainId,\n yourSupplies: state.yourSupplies,\n showWithdrawModal: state.showWithdrawModal,\n setShowWithdrawModal: (isShow) =>\n State.update({ showWithdrawModal: isShow }),\n onActionSuccess,\n healthFactor: formatHealthFactor(\n state.assetsToBorrow.healthFactor\n ),\n formatHealthFactor,\n withdrawETHGas,\n withdrawERC20Gas,\n }}\n />\n <Widget\n src={`deepcryptodive.near/widget/SPARK.Card.AssetsToSupply`}\n props={{\n config,\n chainId: state.chainId,\n assetsToSupply: state.assetsToSupply,\n showSupplyModal: state.showSupplyModal,\n setShowSupplyModal: (isShow) =>\n State.update({ showSupplyModal: isShow }),\n onActionSuccess,\n healthFactor: formatHealthFactor(\n state.assetsToBorrow.healthFactor\n ),\n formatHealthFactor,\n depositETHGas,\n depositERC20Gas,\n }}\n />\n </>\n )}\n {state.selectTab === \"borrow\" && (\n <>\n <Widget\n src={`deepcryptodive.near/widget/ZKEVM.AAVE.Card.YourBorrows`}\n props={{\n config,\n chainId: state.chainId,\n yourBorrows: state.yourBorrows,\n showRepayModal: state.showRepayModal,\n setShowRepayModal: (isShow) =>\n State.update({ showRepayModal: isShow }),\n showBorrowModal: state.showBorrowModal,\n setShowBorrowModal: (isShow) =>\n State.update({ showBorrowModal: isShow }),\n formatHealthFactor,\n onActionSuccess,\n repayETHGas,\n repayERC20Gas,\n borrowETHGas,\n borrowERC20Gas,\n }}\n />\n <Widget\n src={`deepcryptodive.near/widget/SPARK.Card.AssetsToBorrow`}\n props={{\n config,\n chainId: state.chainId,\n assetsToBorrow: state.assetsToBorrow,\n showBorrowModal: state.showBorrowModal,\n yourSupplies: state.yourSupplies,\n setShowBorrowModal: (isShow) =>\n State.update({ showBorrowModal: isShow }),\n formatHealthFactor,\n onActionSuccess,\n borrowETHGas,\n borrowERC20Gas,\n }}\n />\n </>\n )}\n {state.alertModalText && (\n <Widget\n src={`${config.ownerId}/widget/AAVE.Modal.AlertModal`}\n props={{\n config,\n title: \"All done!\",\n description: state.alertModalText,\n onRequestClose: () => State.update({ alertModalText: false }),\n }}\n />\n )}\n </Body>\n </>\n);\n\nreturn (\n <>\n <PageBackground>\n <Widget src=\"guessme.near/widget/ZKEVMWarmUp.generage-uuid\" />\n <AAVEContainer>\n {/* Component Head */}\n <Widget\n src={`${config.ownerId}/widget/Utils.Import`}\n props={{ modules, onLoad: importFunctions }}\n />\n {/* Component Body */}\n {body}\n {/* Add a new widget at the bottom & title*/}\n <StyledContainer>\n <Markdown text={\"## Similar Lending Markets\"} />\n </StyledContainer>\n <Widget src=\"bluebiu.near/widget/Gnosis.Lending\" />\n </AAVEContainer>\n </PageBackground>\n </>\n);\n" } } } } }

Transaction Execution Plan

Convert Transaction To Receipt
Gas Burned:
2 Tgas
Tokens Burned:
0.00025 
Receipt:
Predecessor ID:
Receiver ID:
Gas Burned:
8 Tgas
Tokens Burned:
0.00087 
Called method: 'set' in contract: social.near
Arguments:
{ "data": { "deepcryptodive.near": { "widget": { "SPARK-local": { "": "// Original code on which this is based can be found at https://near.org/near/widget/ComponentDetailsPage?src=bluebiu.near/widget/ZKEVM.AAVE\nconst ROUND_DOWN = 0;\nconst CONTRACT_ABI = {\n wrappedTokenGatewayV3ABI:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/WrappedTokenGatewayV3ABI.json\",\n erc20Abi:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/ERC20Permit.json\",\n aavePoolV3ABI:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/AAVEPoolV3.json\",\n variableDebtTokenABI:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/VariableDebtToken.json\",\n walletBalanceProviderABI:\n \"https://raw.githubusercontent.com/corndao/aave-v3-bos-app/main/abi/WalletBalanceProvider.json\",\n};\nconst DEFAULT_CHAIN_ID = 100;\nconst NATIVE_SYMBOL_ADDRESS_MAP_KEY = \"0x0\";\nconst ETH_TOKEN = { name: \"Ethereum\", symbol: \"ETH\", decimals: 18 };\nconst WETH_TOKEN = { name: \"Wrapped Ether\", symbol: \"WETH\", decimals: 18 };\nconst MATIC_TOKEN = { name: \"Matic\", symbol: \"MATIC\", decimals: 18 };\nconst WMATIC_TOKEN = { name: \"Wrapped Matic\", symbol: \"WMATIC\", decimals: 18 };\nconst XDAI_TOKEN = { name: \"XDAI\", symbol: \"XDAI\", decimals: 18 };\nconst WXDAI_TOKEN = { name: \"Wrapped XDAI\", symbol: \"WXDAI\", decimals: 18 };\nconst ACTUAL_BORROW_AMOUNT_RATE = 0.99;\n\n// Get Spark Lend config by chain id\nfunction getNetworkConfig(chainId) {\n const abis = {\n wrappedTokenGatewayV3ABI: fetch(CONTRACT_ABI.wrappedTokenGatewayV3ABI),\n erc20Abi: fetch(CONTRACT_ABI.erc20Abi),\n aavePoolV3ABI: fetch(CONTRACT_ABI.aavePoolV3ABI),\n variableDebtTokenABI: fetch(CONTRACT_ABI.variableDebtTokenABI),\n walletBalanceProviderABI: fetch(CONTRACT_ABI.walletBalanceProviderABI),\n };\n\n const constants = {\n FIXED_LIQUIDATION_VALUE: \"1.0\",\n MAX_UINT_256:\n \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",\n AAVE_API_BASE_URL: \"http://localhost:8080\",\n // this connects to our custom Spark Protocol Data Service\n // see https://github.com/Deepcryptodive/spark-data-service\n // If you want to run it on localhost, change it to \"http://localhost:8080\"\n // If you want to run it online, change it to \"https://spark-api.pages.dev/\"\n };\n\n switch (chainId) {\n case 1: // ethereum mainnet\n return {\n chainName: \"Ethereum Mainnet\",\n nativeCurrency: ETH_TOKEN,\n nativeWrapCurrency: WETH_TOKEN,\n rpcUrl: \"https://eth-pokt.nodies.app\",\n aavePoolV3Address: \"0xC13e21B648A5Ee794902342038FF3aDAB66BE987\",\n wrappedTokenGatewayV3Address:\n \"0xBD7D6a9ad7865463DE44B05F04559f65e3B11704\",\n balanceProviderAddress: \"0xd2AeF86F51F92E8e49F42454c287AE4879D1BeDc\",\n ...abis,\n ...constants,\n };\n case 42161: // arbitrum one - TO BE REMOVED\n return {\n chainName: \"Arbitrum Mainnet\",\n nativeCurrency: ETH_TOKEN,\n nativeWrapCurrency: WETH_TOKEN,\n rpcUrl: \"https://arb1.arbitrum.io/rpc\",\n aavePoolV3Address: \"0x794a61358D6845594F94dc1DB02A252b5b4814aD\",\n wrappedTokenGatewayV3Address:\n \"0xB5Ee21786D28c5Ba61661550879475976B707099\",\n balanceProviderAddress: \"0xBc790382B3686abffE4be14A030A96aC6154023a\",\n ...abis,\n ...constants,\n };\n case 137: // polygon mainnet - still configured to Aave v3 for debugging!\n return {\n chainName: \"Polygon Mainnet\",\n nativeCurrency: MATIC_TOKEN,\n nativeWrapCurrency: WMATIC_TOKEN,\n rpcUrl: \"https://polygon-pokt.nodies.app\",\n aavePoolV3Address: \"0x794a61358D6845594F94dc1DB02A252b5b4814aD\",\n wrappedTokenGatewayV3Address:\n \"0x1e4b7A6b903680eab0c5dAbcb8fD429cD2a9598c\",\n balanceProviderAddress: \"0xBc790382B3686abffE4be14A030A96aC6154023a\",\n ...abis,\n ...constants,\n };\n case 100: // Gnosis\n return {\n chainName: \"Gnosis Mainnet\",\n nativeCurrency: XDAI_TOKEN,\n nativeWrapCurrency: WXDAI_TOKEN,\n rpcUrl: \"https://gnosis-pokt.nodies.app\",\n aavePoolV3Address: \"0x2Dae5307c5E3FD1CF5A72Cb6F698f915860607e0\",\n wrappedTokenGatewayV3Address:\n \"0xBD7D6a9ad7865463DE44B05F04559f65e3B11704\", // NOTE: not listed in the Spark docs - got it from Gnosisscan\n balanceProviderAddress: \"0xd2AeF86F51F92E8e49F42454c287AE4879D1BeDc\",\n ...abis,\n ...constants,\n };\n case 1442: // zkevm testnet - TO BE REMOVED\n return {\n chainName: \"Polygon zkEVM Testnet\",\n nativeCurrency: ETH_TOKEN,\n nativeWrapCurrency: WETH_TOKEN,\n rpcUrl: \"https://rpc.public.zkevm-test.net\",\n aavePoolV3Address: \"0x4412c92f6579D9FC542D108382c8D1d6D2Be63d9\",\n wrappedTokenGatewayV3Address:\n \"0xD82940E16D25aB1349914e1C369eF1b287d457BF\",\n balanceProviderAddress: \"0x0da6DCAd2bE4801b644AEE679e0AdE008bB4bc6b\",\n ...abis,\n ...constants,\n };\n default:\n throw new Error(\"unknown chain id\");\n }\n}\n\nfunction switchEthereumChain(chainId) {\n const chainIdHex = `0x${chainId.toString(16)}`;\n const res = Ethers.send(\"wallet_switchEthereumChain\", [\n { chainId: chainIdHex },\n ]);\n // If `res` === `undefined`, it means switch chain failed, which is very weird but it works.\n // If `res` is `null` the function is either not called or executed successfully.\n if (res === undefined) {\n console.log(\n `Failed to switch chain to ${chainId}. Add the chain to wallet`\n );\n const config = getNetworkConfig(chainId);\n Ethers.send(\"wallet_addEthereumChain\", [\n {\n chainId: chainIdHex,\n chainName: config.chainName,\n nativeCurrency: config.nativeCurrency,\n rpcUrls: [config.rpcUrl],\n },\n ]);\n }\n}\n\nif (\n state.chainId === undefined &&\n ethers !== undefined &&\n Ethers.send(\"eth_requestAccounts\", [])[0]\n) {\n Ethers.provider()\n .getNetwork()\n .then((data) => {\n const chainId = data?.chainId;\n const config = getNetworkConfig(chainId);\n if (!config) {\n console.log(`Unsupport chain, chainId: ${chainId}`);\n State.update({ isChainSupported: false });\n switchEthereumChain(DEFAULT_CHAIN_ID);\n } else {\n State.update({ chainId, isChainSupported: true });\n }\n });\n}\n\nfunction isValid(a) {\n if (!a) return false;\n if (isNaN(Number(a))) return false;\n if (a === \"\") return false;\n return true;\n}\n\nconst GAS_LIMIT_RECOMMENDATIONS = {\n default: {\n limit: \"210000\",\n recommended: \"210000\",\n },\n approval: {\n limit: \"65000\",\n recommended: \"65000\",\n },\n creditDelegationApproval: {\n limit: \"55000\",\n recommended: \"55000\",\n },\n supply: {\n limit: \"300000\",\n recommended: \"300000\",\n },\n deposit: {\n limit: \"300000\",\n recommended: \"300000\",\n },\n borrow: {\n limit: \"400000\",\n recommended: \"400000\",\n },\n withdraw: {\n limit: \"230000\",\n recommended: \"300000\",\n },\n liquidationCall: {\n limit: \"700000\",\n recommended: \"700000\",\n },\n liquidationFlash: {\n limit: \"995000\",\n recommended: \"995000\",\n },\n repay: {\n limit: \"300000\",\n recommended: \"300000\",\n },\n borrowETH: {\n limit: \"450000\",\n recommended: \"450000\",\n },\n withdrawETH: {\n limit: \"640000\",\n recommended: \"640000\",\n },\n swapCollateral: {\n limit: \"1000000\",\n recommended: \"1000000\",\n },\n repayCollateral: {\n limit: \"700000\",\n recommended: \"700000\",\n },\n migrateV3: {\n limit: \"700000\",\n recommended: \"700000\",\n },\n supplyWithPermit: {\n limit: \"350000\",\n recommended: \"350000\",\n },\n repayWithPermit: {\n limit: \"350000\",\n recommended: \"350000\",\n },\n vote: {\n limit: \"125000\",\n recommended: \"125000\",\n },\n stake: {\n limit: \"395000\",\n recommended: \"395000\",\n },\n claimRewards: {\n limit: \"275000\",\n recommended: \"275000\",\n },\n setUsageAsCollateral: {\n limit: \"138000\",\n recommended: \"138000\",\n },\n};\n\nfunction getGasPrice() {\n return Ethers.provider().getGasPrice();\n}\n\nfunction gasEstimation(action) {\n const assetsToSupply = state.assetsToSupply;\n if (!assetsToSupply) {\n return \"-\";\n }\n const baseAsset = assetsToSupply.find(\n (asset) => asset.symbol === config.nativeCurrency.symbol\n );\n if (!baseAsset) {\n return \"-\";\n }\n const { marketReferencePriceInUsd, decimals } = baseAsset;\n return getGasPrice().then((gasPrice) => {\n const gasLimit = GAS_LIMIT_RECOMMENDATIONS[action].limit;\n return Big(gasPrice.toString())\n .mul(gasLimit)\n .div(Big(10).pow(decimals))\n .mul(marketReferencePriceInUsd)\n .toFixed(2);\n });\n}\n\nfunction depositETHGas() {\n return gasEstimation(\"deposit\");\n}\n\nfunction depositERC20Gas() {\n return gasEstimation(\"supplyWithPermit\");\n}\n\nfunction withdrawETHGas() {\n return gasEstimation(\"withdrawETH\");\n}\n\nfunction withdrawERC20Gas() {\n return gasEstimation(\"withdraw\");\n}\n\nfunction borrowETHGas() {\n return gasEstimation(\"borrowETH\");\n}\n\nfunction borrowERC20Gas() {\n return gasEstimation(\"borrow\");\n}\n\nfunction repayETHGas() {\n return gasEstimation(\"repay\");\n}\n\nfunction repayERC20Gas() {\n return gasEstimation(\"repayWithPermit\");\n}\n\n// interface Market {\n// id: string,\n// underlyingAsset: string,\n// name: string,\n// symbol: string,\n// decimals: number,\n// supplyAPY: string;\n// marketReferencePriceInUsd: string;\n// usageAsCollateralEnabled: boolean;\n// aTokenAddress: string;\n// variableBorrowAPY: string;\n// }\n// returns Market[]\nfunction getMarkets(chainId) {\n return asyncFetch(`${config.AAVE_API_BASE_URL}/${chainId}/markets`);\n}\n\n/**\n * @param {string} account user address\n * @param {string[]} tokens list of token addresses\n */\n// interface TokenBalance {\n// token: string,\n// balance: string,\n// decimals: number,\n// }\n// returns TokenBalance[]\nfunction getUserBalances(chainId, account, tokens) {\n const url = `${\n config.AAVE_API_BASE_URL\n }/${chainId}/balances?account=${account}&tokens=${tokens.join(\"|\")}`;\n return asyncFetch(url);\n}\n\n// interface UserDeposit {\n// underlyingAsset: string,\n// name: string,\n// symbol: string,\n// scaledATokenBalance: string,\n// usageAsCollateralEnabledOnUser: boolean,\n// underlyingBalance: string,\n// underlyingBalanceUSD: string,\n// }\n// returns UserDeposit[]\nfunction getUserDeposits(chainId, address) {\n return asyncFetch(\n `${config.AAVE_API_BASE_URL}/${chainId}/deposits/${address}`\n );\n}\n\n// interface UserDebtSummary {\n// healthFactor: string,\n// netWorthUSD: string,\n// availableBorrowsUSD: string,\n// debts: UserDebt[],\n// }\n// interface UserDebt {\n// underlyingAsset: string;\n// name: string;\n// symbol: string;\n// usageAsCollateralEnabledOnUser: boolean,\n// scaledVariableDebt: string,\n// variableBorrows: string,\n// variableBorrowsUSD: string,\n// }\n// returns UserDebtSummary\nfunction getUserDebts(chainId, address) {\n return asyncFetch(`${config.AAVE_API_BASE_URL}/${chainId}/debts/${address}`);\n}\n\n// App config\nfunction getConfig(network) {\n const chainId = state.chainId;\n switch (network) {\n case \"mainnet\":\n return {\n ownerId: \"aave-v3.near\",\n nodeUrl: \"https://rpc.mainnet.near.org\",\n ipfsPrefix: \"https://ipfs.near.social/ipfs\",\n ...(chainId ? getNetworkConfig(chainId) : {}),\n };\n case \"testnet\":\n return {\n ownerId: \"aave-v3.testnet\",\n nodeUrl: \"https://rpc.testnet.near.org\",\n ipfsPrefix: \"https://ipfs.near.social/ipfs\",\n ...(chainId ? getNetworkConfig(chainId) : {}),\n };\n default:\n throw Error(`Unconfigured environment '${network}'.`);\n }\n}\nconst config = getConfig(context.networkId);\n\n// App states\nState.init({\n imports: {},\n chainId: undefined, // chainId is undefined in the case of unsupported chains\n isChainSupported: true,\n showWithdrawModal: false,\n showSupplyModal: false,\n showRepayModal: false,\n showBorrowModal: false,\n walletConnected: false,\n assetsToSupply: undefined,\n yourSupplies: undefined,\n assetsToBorrow: undefined,\n yourBorrows: undefined,\n address: undefined,\n baseAssetBalance: undefined,\n selectTab: \"supply\", // supply | borrow\n});\n\nconst loading =\n !state.assetsToSupply || !state.yourSupplies || !state.assetsToBorrow;\n\n// Import functions to state.imports\nfunction importFunctions(imports) {\n if (loading) {\n State.update({\n imports,\n });\n }\n}\n\n// Define the modules you'd like to import\nconst modules = {\n number: `${config.ownerId}/widget/Utils.Number`,\n date: `${config.ownerId}/widget/Utils.Date`,\n data: `${config.ownerId}/widget/AAVE.Data`,\n};\n// Import functions\n// const { formatAmount } = state.imports.number;\n// const { formatDateTime } = state.imports.date;\n\nfunction checkProvider() {\n const provider = Ethers.provider();\n if (provider) {\n State.update({ walletConnected: true });\n } else {\n State.update({ walletConnected: false });\n }\n}\n\nfunction calculateAvailableBorrows({\n availableBorrowsUSD,\n marketReferencePriceInUsd,\n}) {\n return isValid(availableBorrowsUSD) && isValid(marketReferencePriceInUsd)\n ? Big(availableBorrowsUSD).div(marketReferencePriceInUsd).toFixed()\n : Number(0).toFixed();\n}\n\nfunction bigMin(_a, _b) {\n const a = Big(_a);\n const b = Big(_b);\n return a.gt(b) ? b : a;\n}\n\nfunction formatHealthFactor(healthFactor) {\n if (healthFactor === \"∞\") return healthFactor;\n if (!healthFactor || !isValid(healthFactor)) return \"-\";\n if (Number(healthFactor) === -1) return \"∞\";\n return Big(healthFactor).toFixed(2, ROUND_DOWN);\n}\n\nfunction batchBalanceOf(chainId, userAddress, tokenAddresses, abi) {\n const balanceProvider = new ethers.Contract(\n config.balanceProviderAddress,\n abi.body,\n Ethers.provider().getSigner()\n );\n\n return balanceProvider.batchBalanceOf([userAddress], tokenAddresses);\n}\n\n// update data in async manner\nfunction updateData(refresh) {\n // check abi loaded\n if (\n Object.keys(CONTRACT_ABI)\n .map((key) => config[key])\n .filter((ele) => !!ele).length !== Object.keys(CONTRACT_ABI).length\n ) {\n return;\n }\n const provider = Ethers.provider();\n if (!provider) {\n return;\n }\n provider\n .getSigner()\n ?.getAddress()\n ?.then((address) => {\n State.update({ address });\n });\n provider\n .getSigner()\n ?.getBalance()\n .then((balance) => State.update({ baseAssetBalance: balance }));\n if (!state.address || !state.baseAssetBalance) {\n return;\n }\n\n getMarkets(state.chainId).then((marketsResponse) => {\n if (!marketsResponse) {\n return;\n }\n const markets = marketsResponse.body;\n const marketsMapping = markets.reduce((prev, cur) => {\n prev[cur.underlyingAsset] = cur;\n return prev;\n }, {});\n\n const nativeMarket = markets.find(\n (market) => market.symbol === config.nativeWrapCurrency.symbol\n );\n markets.push({\n ...nativeMarket,\n ...{\n ...config.nativeCurrency,\n supportPermit: true,\n },\n });\n\n // get user balances\n batchBalanceOf(\n state.chainId,\n state.address,\n markets.map((market) => market.underlyingAsset),\n config.walletBalanceProviderABI\n )\n .then((balances) => balances.map((balance) => balance.toString()))\n .then((userBalances) => {\n const assetsToSupply = markets\n .map((market, idx) => {\n const balanceRaw = Big(\n market.symbol === config.nativeCurrency.symbol\n ? state.baseAssetBalance\n : userBalances[idx]\n ).div(Big(10).pow(market.decimals));\n const balance = balanceRaw.toFixed(market.decimals, ROUND_DOWN);\n const balanceInUSD = balanceRaw\n .mul(market.marketReferencePriceInUsd)\n .toFixed(3, ROUND_DOWN);\n return {\n ...market,\n balance,\n balanceInUSD,\n };\n })\n .sort((asset1, asset2) => {\n const balanceInUSD1 = Number(asset1.balanceInUSD);\n const balanceInUSD2 = Number(asset2.balanceInUSD);\n if (balanceInUSD1 !== balanceInUSD2)\n return balanceInUSD2 - balanceInUSD1;\n return asset1.symbol.localeCompare(asset2.symbol);\n });\n\n State.update({\n assetsToSupply,\n });\n // get user borrow data\n updateUserDebts(marketsMapping, assetsToSupply, refresh);\n });\n // get user supplies\n updateUserSupplies(marketsMapping, refresh);\n });\n}\n\nfunction updateUserSupplies(marketsMapping, refresh) {\n const prevYourSupplies = state.yourSupplies;\n getUserDeposits(state.chainId, state.address).then((userDepositsResponse) => {\n if (!userDepositsResponse) {\n return;\n }\n const userDeposits = userDepositsResponse.body.filter(\n (row) => Number(row.underlyingBalance) !== 0\n );\n const yourSupplies = userDeposits.map((userDeposit) => {\n const market = marketsMapping[userDeposit.underlyingAsset];\n return {\n ...market,\n ...userDeposit,\n ...(market.symbol === config.nativeWrapCurrency.symbol\n ? {\n ...config.nativeCurrency,\n supportPermit: true,\n }\n : {}),\n };\n });\n\n State.update({\n yourSupplies,\n });\n\n if (\n refresh &&\n JSON.stringify(prevYourSupplies) === JSON.stringify(yourSupplies) &&\n yourSupplies.length !== 0\n ) {\n console.log(\"refresh supplies again ...\", prevYourSupplies, yourSupplies);\n setTimeout(updateData, 500);\n }\n });\n}\n\nfunction updateUserDebts(marketsMapping, assetsToSupply, refresh) {\n if (!marketsMapping || !assetsToSupply) {\n return;\n }\n\n const prevYourBorrows = state.yourBorrows;\n // userDebts depends on the balance from assetsToSupply\n const assetsToSupplyMap = assetsToSupply.reduce((prev, cur) => {\n if (cur.symbol !== config.nativeCurrency.symbol) {\n prev[cur.underlyingAsset] = cur;\n } else {\n prev[NATIVE_SYMBOL_ADDRESS_MAP_KEY] = cur;\n }\n return prev;\n }, {});\n\n getUserDebts(state.chainId, state.address).then((userDebtsResponse) => {\n if (!userDebtsResponse) {\n return;\n }\n const userDebts = userDebtsResponse.body;\n const assetsToBorrow = {\n ...userDebts,\n healthFactor: formatHealthFactor(userDebts.healthFactor),\n debts: userDebts.debts\n .map((userDebt) => {\n const market = marketsMapping[userDebt.underlyingAsset];\n if (!market) {\n return;\n }\n const { availableLiquidityUSD } = market;\n const availableBorrowsUSD = bigMin(\n userDebts.availableBorrowsUSD,\n availableLiquidityUSD\n )\n .times(ACTUAL_BORROW_AMOUNT_RATE)\n .toFixed();\n const assetsToSupplyMapKey =\n market.symbol === config.nativeWrapCurrency.symbol\n ? NATIVE_SYMBOL_ADDRESS_MAP_KEY\n : userDebt.underlyingAsset;\n return {\n ...market,\n ...userDebt,\n ...(market.symbol === config.nativeWrapCurrency.symbol\n ? {\n ...config.nativeCurrency,\n supportPermit: true,\n }\n : {}),\n availableBorrows: calculateAvailableBorrows({\n availableBorrowsUSD,\n marketReferencePriceInUsd: market.marketReferencePriceInUsd,\n }),\n availableBorrowsUSD,\n balance: assetsToSupplyMap[assetsToSupplyMapKey].balance,\n balanceInUSD: assetsToSupplyMap[assetsToSupplyMapKey].balanceInUSD,\n };\n })\n .filter((asset) => !!asset)\n .sort((asset1, asset2) => {\n const availableBorrowsUSD1 = Number(asset1.availableBorrowsUSD);\n const availableBorrowsUSD2 = Number(asset2.availableBorrowsUSD);\n if (availableBorrowsUSD1 !== availableBorrowsUSD2)\n return availableBorrowsUSD2 - availableBorrowsUSD1;\n return asset1.symbol.localeCompare(asset2.symbol);\n })\n .filter((asset) => {\n return asset.borrowingEnabled;\n }),\n };\n const yourBorrows = {\n ...assetsToBorrow,\n debts: assetsToBorrow.debts.filter(\n (row) =>\n !isNaN(Number(row.variableBorrowsUSD)) &&\n Number(row.variableBorrowsUSD) > 0\n ),\n };\n\n State.update({\n yourBorrows,\n assetsToBorrow,\n });\n\n if (\n refresh &&\n JSON.stringify(prevYourBorrows) === JSON.stringify(yourBorrows)\n ) {\n console.log(\"refresh borrows again ...\", prevYourBorrows, yourBorrows);\n setTimeout(updateData, 500);\n }\n });\n}\n\nfunction onActionSuccess({ msg, callback }) {\n // update data if action finishes\n updateData(true);\n // update UI after data has almost loaded\n setTimeout(() => {\n if (callback) {\n callback();\n }\n if (msg) {\n State.update({ alertModalText: msg });\n }\n }, 5000);\n}\n\ncheckProvider();\nif (state.walletConnected && state.chainId && loading) {\n updateData();\n}\n\nconst PageBackground = styled.div`\n background-color: #1e202f;\n`;\n\nconst StyledContainer = styled.div`\n color: white;\n border: 1px solid white;\n padding-top: 1rem;\n min-width: 100%;\n text-align: center;\n`;\n\nconst Body = styled.div`\n padding-top: 24px;\n min-height: 100vh;\n color: white;\n .top-title {\n display: flex;\n justify-content: space-between;\n line-height: 48px;\n }\n`;\n\nconst FlexContainer = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n flex-direction: column;\n`;\nconst TopContainer = styled.div`\n display: flex;\n justify-content: space-between;\n align-items: center;\n .tabSwitcher {\n border: 1px solid #332c4b;\n background: #222436;\n border-radius: 10px;\n }\n .networkSwitcher {\n border: 1px solid #332c4b;\n background: #222436;\n border-radius: 10px;\n padding: 8px 12px 8px 0;\n }\n`;\nconst AAVEContainer = styled.div`\n width: 100%;\n margin: 0 auto;\n padding-bottom: 50px;\n .tip {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n }\n`;\nconst TitleText = styled.div`\n font-size: 20px;\n font-weight: 700;\n margin-bottom: 32px;\n color: #ffffff;\n`;\n// Component body\nconst body = loading ? (\n <>\n <Body>\n <TitleText>SparkNexus</TitleText>\n <div className=\"load\">\n <Widget\n src={`deepcryptodive.near/widget/SPARK.Loader`}\n props={{\n walletConnected: state.walletConnected,\n isChainSupported: state.isChainSupported,\n chainId: state.chainId,\n DEFAULT_CHAIN_ID,\n getNetworkConfig,\n }}\n />\n </div>\n </Body>\n </>\n) : (\n <>\n <Body>\n <div className=\"top-title\">\n <TitleText>Spark Protocol</TitleText>\n <div className=\"tabSwitcher\">\n <Widget\n src={`guessme.near/widget/ZKEVM.AAVE.TabSwitcher`}\n props={{\n config,\n select: state.selectTab,\n setSelect: (tabName) => State.update({ selectTab: tabName }),\n }}\n />\n </div>\n </div>\n <TopContainer>\n <Widget\n src={`bluebiu.near/widget/ZKEVM.AAVE.HeroData`}\n props={{\n config,\n netWorth: `$ ${\n state.assetsToBorrow?.netWorthUSD\n ? Big(state.assetsToBorrow.netWorthUSD).toFixed(2)\n : \"-\"\n }`,\n netApy: `${\n state.assetsToBorrow?.netAPY\n ? Number(\n Big(state.assetsToBorrow.netAPY).times(100).toFixed(2)\n ) === 0\n ? \"0.00\"\n : Big(state.assetsToBorrow.netAPY).times(100).toFixed(2)\n : \"-\"\n }%`,\n healthFactor: formatHealthFactor(state.assetsToBorrow.healthFactor),\n showHealthFactor:\n state.yourBorrows &&\n state.yourBorrows.debts &&\n state.yourBorrows.debts.length > 0,\n }}\n />\n <div className=\"networkSwitcher\">\n <Widget\n src={`deepcryptodive.near/widget/SPARK.NetworkSwitcher`}\n props={{\n chainId: state.chainId,\n config,\n switchNetwork: (chainId) => {\n switchEthereumChain(chainId);\n },\n }}\n />\n </div>\n </TopContainer>\n {state.selectTab === \"supply\" && (\n <>\n <Widget\n src={`deepcryptodive.near/widget/SPARK.Card.YourSupplies`}\n props={{\n config,\n chainId: state.chainId,\n yourSupplies: state.yourSupplies,\n showWithdrawModal: state.showWithdrawModal,\n setShowWithdrawModal: (isShow) =>\n State.update({ showWithdrawModal: isShow }),\n onActionSuccess,\n healthFactor: formatHealthFactor(\n state.assetsToBorrow.healthFactor\n ),\n formatHealthFactor,\n withdrawETHGas,\n withdrawERC20Gas,\n }}\n />\n <Widget\n src={`deepcryptodive.near/widget/SPARK.Card.AssetsToSupply`}\n props={{\n config,\n chainId: state.chainId,\n assetsToSupply: state.assetsToSupply,\n showSupplyModal: state.showSupplyModal,\n setShowSupplyModal: (isShow) =>\n State.update({ showSupplyModal: isShow }),\n onActionSuccess,\n healthFactor: formatHealthFactor(\n state.assetsToBorrow.healthFactor\n ),\n formatHealthFactor,\n depositETHGas,\n depositERC20Gas,\n }}\n />\n </>\n )}\n {state.selectTab === \"borrow\" && (\n <>\n <Widget\n src={`deepcryptodive.near/widget/ZKEVM.AAVE.Card.YourBorrows`}\n props={{\n config,\n chainId: state.chainId,\n yourBorrows: state.yourBorrows,\n showRepayModal: state.showRepayModal,\n setShowRepayModal: (isShow) =>\n State.update({ showRepayModal: isShow }),\n showBorrowModal: state.showBorrowModal,\n setShowBorrowModal: (isShow) =>\n State.update({ showBorrowModal: isShow }),\n formatHealthFactor,\n onActionSuccess,\n repayETHGas,\n repayERC20Gas,\n borrowETHGas,\n borrowERC20Gas,\n }}\n />\n <Widget\n src={`deepcryptodive.near/widget/SPARK.Card.AssetsToBorrow`}\n props={{\n config,\n chainId: state.chainId,\n assetsToBorrow: state.assetsToBorrow,\n showBorrowModal: state.showBorrowModal,\n yourSupplies: state.yourSupplies,\n setShowBorrowModal: (isShow) =>\n State.update({ showBorrowModal: isShow }),\n formatHealthFactor,\n onActionSuccess,\n borrowETHGas,\n borrowERC20Gas,\n }}\n />\n </>\n )}\n {state.alertModalText && (\n <Widget\n src={`${config.ownerId}/widget/AAVE.Modal.AlertModal`}\n props={{\n config,\n title: \"All done!\",\n description: state.alertModalText,\n onRequestClose: () => State.update({ alertModalText: false }),\n }}\n />\n )}\n </Body>\n </>\n);\n\nreturn (\n <>\n <PageBackground>\n <Widget src=\"guessme.near/widget/ZKEVMWarmUp.generage-uuid\" />\n <AAVEContainer>\n {/* Component Head */}\n <Widget\n src={`${config.ownerId}/widget/Utils.Import`}\n props={{ modules, onLoad: importFunctions }}\n />\n {/* Component Body */}\n {body}\n {/* Add a new widget at the bottom & title*/}\n <StyledContainer>\n <Markdown text={\"## Similar Lending Markets\"} />\n </StyledContainer>\n <Widget src=\"bluebiu.near/widget/Gnosis.Lending\" />\n </AAVEContainer>\n </PageBackground>\n </>\n);\n" } } } } }
Empty result
No logs
Receipt:
Predecessor ID:
Gas Burned:
223 Ggas
Tokens Burned:
0 
Transferred 0.0182  to deepcryptodive.near
Empty result
No logs