From ed128bb71fa30900ecf778a22c1b65f7be9ef9f3 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:48:40 -0400 Subject: [PATCH 01/96] update IWell.sol --- protocol/contracts/interfaces/basin/IWell.sol | 162 +++++++++++------- 1 file changed, 96 insertions(+), 66 deletions(-) diff --git a/protocol/contracts/interfaces/basin/IWell.sol b/protocol/contracts/interfaces/basin/IWell.sol index 84f0f8e5a0..bdb3dfe83c 100644 --- a/protocol/contracts/interfaces/basin/IWell.sol +++ b/protocol/contracts/interfaces/basin/IWell.sol @@ -15,6 +15,10 @@ struct Call { /** * @title IWell is the interface for the Well contract. + * + * In order for a Well to be verified using a permissionless on-chain registry, a Well Implementation should: + * - Not be able to self-destruct (Aquifer's registry would be vulnerable to a metamorphic contract attack) + * - Not be able to change its tokens, Well Function, Pumps and Well Data */ interface IWell { /** @@ -23,53 +27,55 @@ interface IWell { * @param toToken The token swapped to * @param amountIn The amount of `fromToken` transferred into the Well * @param amountOut The amount of `toToken` transferred out of the Well - * @param recipient The address to receive `toToken` + * @param recipient The address that received `toToken` */ - event Swap(IERC20 fromToken, IERC20 toToken, uint amountIn, uint amountOut, address recipient); + event Swap(IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 amountOut, address recipient); /** * @notice Emitted when liquidity is added to the Well. * @param tokenAmountsIn The amount of each token added to the Well * @param lpAmountOut The amount of LP tokens minted - * @param recipient The address to receive the LP tokens + * @param recipient The address that received the LP tokens */ - event AddLiquidity(uint[] tokenAmountsIn, uint lpAmountOut, address recipient); + event AddLiquidity(uint256[] tokenAmountsIn, uint256 lpAmountOut, address recipient); /** * @notice Emitted when liquidity is removed from the Well as multiple underlying tokens. * @param lpAmountIn The amount of LP tokens burned * @param tokenAmountsOut The amount of each underlying token removed - * @param recipient The address to receive the underlying tokens + * @param recipient The address that received the underlying tokens * @dev Gas cost scales with `n` tokens. */ - event RemoveLiquidity(uint lpAmountIn, uint[] tokenAmountsOut, address recipient); + event RemoveLiquidity(uint256 lpAmountIn, uint256[] tokenAmountsOut, address recipient); /** * @notice Emitted when liquidity is removed from the Well as a single underlying token. * @param lpAmountIn The amount of LP tokens burned * @param tokenOut The underlying token removed * @param tokenAmountOut The amount of `tokenOut` removed - * @param recipient The address to receive the underlying tokens + * @param recipient The address that received the underlying tokens * @dev Emitting a separate event when removing liquidity as a single token * saves gas, since `tokenAmountsOut` in {RemoveLiquidity} must emit a value * for each token in the Well. */ - event RemoveLiquidityOneToken(uint lpAmountIn, IERC20 tokenOut, uint tokenAmountOut, address recipient); + event RemoveLiquidityOneToken(uint256 lpAmountIn, IERC20 tokenOut, uint256 tokenAmountOut, address recipient); /** * @notice Emitted when a Shift occurs. * @param reserves The ending reserves after a shift * @param toToken The token swapped to - * @param minAmountOut The minimum amount of `toToken` transferred out of the Well - * @param recipient The address to receive `toToken` + * @param amountOut The amount of `toToken` transferred out of the Well + * @param recipient The address that received `toToken` */ - event Shift(uint[] reserves, IERC20 toToken, uint minAmountOut, address recipient); + event Shift(uint256[] reserves, IERC20 toToken, uint256 amountOut, address recipient); /** * @notice Emitted when a Sync occurs. * @param reserves The ending reserves after a sync + * @param lpAmountOut The amount of LP tokens received from the sync. + * @param recipient The address that received the LP tokens */ - event Sync(uint[] reserves); + event Sync(uint256[] reserves, uint256 lpAmountOut, address recipient); //////////////////// WELL DEFINITION //////////////////// @@ -149,11 +155,11 @@ interface IWell { function swapFrom( IERC20 fromToken, IERC20 toToken, - uint amountIn, - uint minAmountOut, + uint256 amountIn, + uint256 minAmountOut, address recipient, - uint deadline - ) external returns (uint amountOut); + uint256 deadline + ) external returns (uint256 amountOut); /** * @notice Swaps from an exact amount of `fromToken` to a minimum amount of `toToken` and supports fee on transfer tokens. @@ -169,11 +175,11 @@ interface IWell { function swapFromFeeOnTransfer( IERC20 fromToken, IERC20 toToken, - uint amountIn, - uint minAmountOut, + uint256 amountIn, + uint256 minAmountOut, address recipient, - uint deadline - ) external returns (uint amountOut); + uint256 deadline + ) external returns (uint256 amountOut); /** * @notice Gets the amount of one token received for swapping an amount of another token. @@ -182,7 +188,7 @@ interface IWell { * @param amountIn The amount of `fromToken` to spend * @return amountOut The amount of `toToken` to receive */ - function getSwapOut(IERC20 fromToken, IERC20 toToken, uint amountIn) external view returns (uint amountOut); + function getSwapOut(IERC20 fromToken, IERC20 toToken, uint256 amountIn) external view returns (uint256 amountOut); //////////////////// SWAP: TO //////////////////// @@ -199,11 +205,11 @@ interface IWell { function swapTo( IERC20 fromToken, IERC20 toToken, - uint maxAmountIn, - uint amountOut, + uint256 maxAmountIn, + uint256 amountOut, address recipient, - uint deadline - ) external returns (uint amountIn); + uint256 deadline + ) external returns (uint256 amountIn); /** * @notice Gets the amount of one token that must be spent to receive an amount of another token during a swap. @@ -212,28 +218,28 @@ interface IWell { * @param amountOut The amount of `toToken` desired * @return amountIn The amount of `fromToken` that must be spent */ - function getSwapIn(IERC20 fromToken, IERC20 toToken, uint amountOut) external view returns (uint amountIn); + function getSwapIn(IERC20 fromToken, IERC20 toToken, uint256 amountOut) external view returns (uint256 amountIn); //////////////////// SHIFT //////////////////// /** - * @notice Shifts excess tokens held by the Well into `tokenOut` and delivers to `recipient`. + * @notice Shifts at least `minAmountOut` excess tokens held by the Well into `tokenOut` and delivers to `recipient`. * @param tokenOut The token to shift into * @param minAmountOut The minimum amount of `tokenOut` to receive * @param recipient The address to receive the token * @return amountOut The amount of `tokenOut` received - * @dev Gas optimization: we leave the responsibility of checking a transaction - * deadline to a wrapper contract like {Pipeline} to prevent repeated deadline - * checks on each hop of a multi-step transaction. + * @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient swaps. + * No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall, + * then a deadline check can be added to the multicall. */ - function shift(IERC20 tokenOut, uint minAmountOut, address recipient) external returns (uint amountOut); + function shift(IERC20 tokenOut, uint256 minAmountOut, address recipient) external returns (uint256 amountOut); /** * @notice Calculates the amount of the token out received from shifting excess tokens held by the Well. * @param tokenOut The token to shift into * @return amountOut The amount of `tokenOut` received */ - function getShiftOut(IERC20 tokenOut) external returns (uint amountOut); + function getShiftOut(IERC20 tokenOut) external returns (uint256 amountOut); //////////////////// ADD LIQUIDITY //////////////////// @@ -246,11 +252,11 @@ interface IWell { * @return lpAmountOut The amount of LP tokens received */ function addLiquidity( - uint[] memory tokenAmountsIn, - uint minLpAmountOut, + uint256[] memory tokenAmountsIn, + uint256 minLpAmountOut, address recipient, - uint deadline - ) external returns (uint lpAmountOut); + uint256 deadline + ) external returns (uint256 lpAmountOut); /** * @notice Adds liquidity to the Well as multiple tokens in any ratio and supports @@ -263,18 +269,18 @@ interface IWell { * @dev Can also be used for tokens without a fee on transfer, but is less gas efficient. */ function addLiquidityFeeOnTransfer( - uint[] memory tokenAmountsIn, - uint minLpAmountOut, + uint256[] memory tokenAmountsIn, + uint256 minLpAmountOut, address recipient, - uint deadline - ) external returns (uint lpAmountOut); + uint256 deadline + ) external returns (uint256 lpAmountOut); /** * @notice Gets the amount of LP tokens received from adding liquidity as multiple tokens in any ratio. * @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens} - * @return lpAmountOut The amount of LP tokens to receive + * @return lpAmountOut The amount of LP tokens received */ - function getAddLiquidityOut(uint[] memory tokenAmountsIn) external view returns (uint lpAmountOut); + function getAddLiquidityOut(uint256[] memory tokenAmountsIn) external view returns (uint256 lpAmountOut); //////////////////// REMOVE LIQUIDITY: BALANCED //////////////////// @@ -287,18 +293,18 @@ interface IWell { * @return tokenAmountsOut The amount of each underlying token received */ function removeLiquidity( - uint lpAmountIn, - uint[] calldata minTokenAmountsOut, + uint256 lpAmountIn, + uint256[] calldata minTokenAmountsOut, address recipient, - uint deadline - ) external returns (uint[] memory tokenAmountsOut); + uint256 deadline + ) external returns (uint256[] memory tokenAmountsOut); /** * @notice Gets the amount of each underlying token received from removing liquidity in a balanced ratio. * @param lpAmountIn The amount of LP tokens to burn - * @return tokenAmountsOut The amount of each underlying token to receive + * @return tokenAmountsOut The amount of each underlying token received */ - function getRemoveLiquidityOut(uint lpAmountIn) external view returns (uint[] memory tokenAmountsOut); + function getRemoveLiquidityOut(uint256 lpAmountIn) external view returns (uint256[] memory tokenAmountsOut); //////////////////// REMOVE LIQUIDITY: ONE TOKEN //////////////////// @@ -312,24 +318,24 @@ interface IWell { * @return tokenAmountOut The amount of `tokenOut` received */ function removeLiquidityOneToken( - uint lpAmountIn, + uint256 lpAmountIn, IERC20 tokenOut, - uint minTokenAmountOut, + uint256 minTokenAmountOut, address recipient, - uint deadline - ) external returns (uint tokenAmountOut); + uint256 deadline + ) external returns (uint256 tokenAmountOut); /** * @notice Gets the amount received from removing liquidity from the Well as a single underlying token. * @param lpAmountIn The amount of LP tokens to burn * @param tokenOut The underlying token to receive - * @return tokenAmountOut The amount of `tokenOut` to receive + * @return tokenAmountOut The amount of `tokenOut` received * */ function getRemoveLiquidityOneTokenOut( - uint lpAmountIn, + uint256 lpAmountIn, IERC20 tokenOut - ) external view returns (uint tokenAmountOut); + ) external view returns (uint256 tokenAmountOut); //////////////////// REMOVE LIQUIDITY: IMBALANCED //////////////////// @@ -341,35 +347,59 @@ interface IWell { * @return lpAmountIn The amount of LP tokens burned */ function removeLiquidityImbalanced( - uint maxLpAmountIn, - uint[] calldata tokenAmountsOut, + uint256 maxLpAmountIn, + uint256[] calldata tokenAmountsOut, address recipient, - uint deadline - ) external returns (uint lpAmountIn); + uint256 deadline + ) external returns (uint256 lpAmountIn); /** * @notice Gets the amount of LP tokens to burn from removing liquidity as multiple underlying tokens in any ratio. * @param tokenAmountsOut The amount of each underlying token to receive; MUST match the indexing of {Well.tokens} - * @return lpAmountIn The amount of LP tokens to burn + * @return lpAmountIn The amount of LP tokens burned */ - function getRemoveLiquidityImbalancedIn(uint[] calldata tokenAmountsOut) external view returns (uint lpAmountIn); + function getRemoveLiquidityImbalancedIn(uint256[] calldata tokenAmountsOut) + external + view + returns (uint256 lpAmountIn); //////////////////// RESERVES //////////////////// /** - * @notice Syncs the reserves of the Well with the Well's balances of underlying tokens. + * @notice Syncs the Well's reserves with the Well's balances of underlying tokens. If the reserves + * increase, mints at least `minLpAmountOut` LP Tokens to `recipient`. + * @param recipient The address to receive the LP tokens + * @param minLpAmountOut The minimum amount of LP tokens to receive + * @return lpAmountOut The amount of LP tokens received + * @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient additions of liquidity. + * No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall, + * then a deadline check can be added to the multicall. + * If `sync` decreases the Well's reserves, then no LP tokens are minted and `lpAmountOut` must be 0. */ - function sync() external; + function sync(address recipient, uint256 minLpAmountOut) external returns (uint256 lpAmountOut); + + /** + * @notice Calculates the amount of LP Tokens received from syncing the Well's reserves with the Well's balances. + * @return lpAmountOut The amount of LP tokens received + */ + function getSyncOut() external view returns (uint256 lpAmountOut); /** * @notice Sends excess tokens held by the Well to the `recipient`. * @param recipient The address to send the tokens * @return skimAmounts The amount of each token skimmed + * @dev No deadline is needed since this function does not use the user's assets. */ - function skim(address recipient) external returns (uint[] memory skimAmounts); + function skim(address recipient) external returns (uint256[] memory skimAmounts); /** * @notice Gets the reserves of each token held by the Well. */ - function getReserves() external view returns (uint[] memory reserves); -} + function getReserves() external view returns (uint256[] memory reserves); + + /** + * @notice Returns whether or not the Well is initialized if it requires initialization. + * If a Well does not require initialization, it should always return `true`. + */ + function isInitialized() external view returns (bool); +} \ No newline at end of file From c4e84bd4a313b7ad91fb0eb390df9dc16a4a537b Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:50:04 -0400 Subject: [PATCH 02/96] Mint Fertilizer with WETH and add liquidity to Bean:Eth Well instead of USDC + Bean:3Crv Curve pool --- .../beanstalk/barn/FertilizerFacet.sol | 77 ++++++-- .../contracts/libraries/LibFertilizer.sol | 65 ++++--- protocol/test/Fertilizer.test.js | 170 ++++++++++-------- 3 files changed, 201 insertions(+), 111 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index a6b8b36de0..fdcc4179f6 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -5,10 +5,16 @@ pragma solidity ^0.7.6; pragma experimental ABIEncoderV2; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol"; +import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; +import {IFertilizer} from "contracts/interfaces/IFertilizer.sol"; import {AppStorage} from "../AppStorage.sol"; -import "contracts/libraries/Token/LibTransfer.sol"; -import "contracts/libraries/LibFertilizer.sol"; -import "contracts/C.sol"; +import {LibTransfer} from "contracts/libraries/Token/LibTransfer.sol"; +import {LibEthUsdOracle} from "contracts/libraries/Oracle/LibEthUsdOracle.sol"; +import {LibFertilizer} from "contracts/libraries/LibFertilizer.sol"; +import {LibSafeMath128} from "contracts/libraries/LibSafeMath128.sol"; +import {C} from "contracts/C.sol"; import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; /** @@ -18,6 +24,7 @@ import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; contract FertilizerFacet { using SafeMath for uint256; + using SafeCast for uint256; using LibSafeMath128 for uint128; event SetFertilizer(uint128 id, uint128 bpf); @@ -37,39 +44,79 @@ contract FertilizerFacet { LibTransfer.sendToken(C.bean(), amount, msg.sender, mode); } + /** + * @dev Returns the amount of Fertilize that can be purchased with `wethAmountIn` WETH. + * Can be used to help calculate `minFertilizerOut` in `mintFertilizer` + */ + function getMintFertilizerOut( + uint128 wethAmountIn + ) external view returns (uint256 fertilizerAmountOut) { + fertilizerAmountOut = amount.mul( + LibEthUsdOracle.getEthUsdPrice() + ).div(1e24); + } + + /** + * @notice Purchase Fertilizer from the Barn Raise with WETH. + * @param wethAmountIn Amount of WETH to buy Fertilizer with 18 decimal precision. + * @param minFertilizerOut The minimum amount of Fertilizer to purchase. + * @param minLP The minimum amount of LP to receive after. + * @param mode The balance to transfer Beans to; see {LibTrasfer.To} + * @dev The # of Fertilizer minted is equal to the value of the Ether paid in USD. + */ function mintFertilizer( - uint128 amount, + uint256 wethAmountIn, + uint256 minFertilizerOut, uint256 minLP, LibTransfer.From mode - ) external payable { - uint128 remaining = uint128(LibFertilizer.remainingRecapitalization().div(1e6)); // remaining <= 77_000_000 so downcasting is safe. - if (amount > remaining) amount = remaining; - amount = uint128(LibTransfer.receiveToken( - C.usdc(), - uint256(amount).mul(1e6), + ) external payable returns (uint256 fertilizerAmountOut) { + + amount = LibTransfer.receiveToken( + IERC20(C.WETH), + uint256(amount), msg.sender, mode - ).div(1e6)); // return value <= amount, so downcasting is safe. + ); // return value <= amount, so downcasting is safe. + + // Convert from Ether amount with 18 decimals to USD amount with 0 decimals. + fertilizerAmountOut = amount.mul( + LibEthUsdOracle.getEthUsdPrice() + ).div(1e24); + + require(fertilizerAmountOut >= minFertilizerOut, "Fertilizer Not enough bought."); + + uint128 remaining = uint128(LibFertilizer.remainingRecapitalization().div(1e6)); // remaining <= 77_000_000 so downcasting is safe. + require(fertilizerAmountOut <= remaining, "Fertilizer: Not enough remaining."); + uint128 id = LibFertilizer.addFertilizer( uint128(s.season.current), amount, + fertilizerAmountOut, minLP ); - C.fertilizer().beanstalkMint(msg.sender, uint256(id), amount, s.bpf); + C.fertilizer().beanstalkMint(msg.sender, uint256(id), (fertilizerAmountOut).toUint128(), s.bpf); } + /** + * @notice Contributes to Barn Raise on behalf of existing fertilizer holders. + */ function addFertilizerOwner( uint128 id, uint128 amount, uint256 minLP ) external payable { LibDiamond.enforceIsContractOwner(); - C.usdc().transferFrom( + IERC20(C.WETH).transferFrom( msg.sender, address(this), - uint256(amount).mul(1e6) + uint256(amount) ); - LibFertilizer.addFertilizer(id, amount, minLP); + + uint256 fertilizerAmount = uint256(amount).mul( + LibEthUsdOracle.getEthUsdPrice() + ).div(1e24); + + LibFertilizer.addFertilizer(id, amount, fertilizerAmount, minLP); } function payFertilizer(address account, uint256 amount) external payable { diff --git a/protocol/contracts/libraries/LibFertilizer.sol b/protocol/contracts/libraries/LibFertilizer.sol index 583b0c63af..f59cbfb6ea 100644 --- a/protocol/contracts/libraries/LibFertilizer.sol +++ b/protocol/contracts/libraries/LibFertilizer.sol @@ -5,11 +5,14 @@ pragma solidity =0.7.6; pragma experimental ABIEncoderV2; -import "@openzeppelin/contracts/math/SafeMath.sol"; -import "./LibAppStorage.sol"; -import "./LibSafeMath128.sol"; -import "../C.sol"; -import "./LibUnripe.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol"; +import {AppStorage, LibAppStorage} from "./LibAppStorage.sol"; +import {LibSafeMath128} from "./LibSafeMath128.sol"; +import {C} from "../C.sol"; +import {LibUnripe} from "./LibUnripe.sol"; +import {IWell} from "contracts/interfaces/basin/IWell.sol"; /** * @author Publius @@ -19,6 +22,7 @@ import "./LibUnripe.sol"; library LibFertilizer { using SafeMath for uint256; using LibSafeMath128 for uint128; + using SafeCast for uint256; event SetFertilizer(uint128 id, uint128 bpf); @@ -31,27 +35,30 @@ library LibFertilizer { function addFertilizer( uint128 season, - uint128 amount, + uint256 amount, + uint256 fertilizerAmount, uint256 minLP ) internal returns (uint128 id) { AppStorage storage s = LibAppStorage.diamondStorage(); - uint256 _amount = uint256(amount); + + uint128 fertilizerAmount128 = fertilizerAmount.toUint128(); + // Calculate Beans Per Fertilizer and add to total owed uint128 bpf = getBpf(season); s.unfertilizedIndex = s.unfertilizedIndex.add( - _amount.mul(uint128(bpf)) + fertilizerAmount.mul(bpf) ); // Get id id = s.bpf.add(bpf); // Update Total and Season supply - s.fertilizer[id] = s.fertilizer[id].add(amount); - s.activeFertilizer = s.activeFertilizer.add(_amount); + s.fertilizer[id] = s.fertilizer[id].add(fertilizerAmount128); + s.activeFertilizer = s.activeFertilizer.add(fertilizerAmount); // Add underlying to Unripe Beans and Unripe LP - addUnderlying(_amount.mul(DECIMALS), minLP); + addUnderlying(amount, fertilizerAmount.mul(DECIMALS), minLP); // If not first time adding Fertilizer with this id, return - if (s.fertilizer[id] > amount) return id; + if (s.fertilizer[id] > fertilizerAmount128) return id; // If first time, log end Beans Per Fertilizer and add to Season queue. - LibFertilizer.push(id); + push(id); emit SetFertilizer(id, bpf); } @@ -66,10 +73,10 @@ library LibFertilizer { humidity = RESTART_HUMIDITY.sub(humidityDecrease); } - function addUnderlying(uint256 amount, uint256 minAmountOut) internal { + function addUnderlying(uint256 amount, uint256 usdAmount, uint256 minAmountOut) internal { AppStorage storage s = LibAppStorage.diamondStorage(); // Calculate how many new Deposited Beans will be minted - uint256 percentToFill = amount.mul(C.precision()).div( + uint256 percentToFill = usdAmount.mul(C.precision()).div( remainingRecapitalization() ); uint256 newDepositedBeans; @@ -83,25 +90,37 @@ library LibFertilizer { } // Calculate how many Beans to add as LP - uint256 newDepositedLPBeans = amount.mul(C.exploitAddLPRatio()).div( + uint256 newDepositedLPBeans = usdAmount.mul(C.exploitAddLPRatio()).div( DECIMALS ); - // Mint the Beans + + // Mint the Deposited Beans to Beanstalk. C.bean().mint( address(this), - newDepositedBeans.add(newDepositedLPBeans) + newDepositedBeans + ); + + // Mint the LP Beans to the Well to sync. + C.bean().mint( + address(C.BEAN_ETH_WELL), + newDepositedLPBeans ); - // Add Liquidity - uint256 newLP = C.curveZap().add_liquidity( - C.CURVE_BEAN_METAPOOL, - [newDepositedLPBeans, 0, amount, 0], + + IERC20(C.WETH).transfer( + address(C.BEAN_ETH_WELL), + amount + ); + + uint256 newLP = IWell(C.BEAN_ETH_WELL).sync( + address(this), minAmountOut ); + // Increment underlying balances of Unripe Tokens LibUnripe.incrementUnderlying(C.UNRIPE_BEAN, newDepositedBeans); LibUnripe.incrementUnderlying(C.UNRIPE_LP, newLP); - s.recapitalized = s.recapitalized.add(amount); + s.recapitalized = s.recapitalized.add(usdAmount); } function push(uint128 id) internal { diff --git a/protocol/test/Fertilizer.test.js b/protocol/test/Fertilizer.test.js index f0a608fa84..4519aef102 100644 --- a/protocol/test/Fertilizer.test.js +++ b/protocol/test/Fertilizer.test.js @@ -1,10 +1,12 @@ const { expect } = require('chai'); const { deploy } = require('../scripts/deploy.js') -const { deployFertilizer, impersonateFertilizer } = require('../scripts/deployFertilizer.js') +const { impersonateFertilizer } = require('../scripts/deployFertilizer.js') const { EXTERNAL, INTERNAL } = require('./utils/balances.js') -const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); -const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP } = require('./utils/constants'); +const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot.js"); +const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK } = require('./utils/constants.js'); +const { setEthUsdcPrice, setEthUsdPrice } = require('../utils/oracle.js'); const { to6, to18 } = require('./utils/helpers.js'); +const { deployBasin } = require('../scripts/basin.js'); let user,user2,owner,fert let userAddress, ownerAddress, user2Address @@ -41,23 +43,36 @@ describe('Fertilize', function () { this.token = await ethers.getContractAt('TokenFacet', this.diamond.address) this.usdc = await ethers.getContractAt('IBean', USDC) this.bean = await ethers.getContractAt('IBean', BEAN) - this.beanMetapool = await ethers.getContractAt('IBean', BEAN_3_CURVE) - this.threeCurve = await ethers.getContractAt('IBean', THREE_CURVE) + this.well = await ethers.getContractAt('IBean', BEAN_3_CURVE) + this.weth = await ethers.getContractAt('IBean', THREE_CURVE) + this.weth = await ethers.getContractAt('IBean', WETH) this.unripeBean = await ethers.getContractAt('MockToken', UNRIPE_BEAN) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) await this.unripeBean.mint(user2.address, to6('1000')) await this.unripeLP.mint(user2.address, to6('942.297473')) - this.threeCurve = await ethers.getContractAt('IBean', THREE_CURVE) - this.threeCurve = await ethers.getContractAt('IBean', THREE_CURVE) + this.weth = await ethers.getContractAt('IBean', WETH) + + await this.bean.mint(owner.address, to18('1000000000')); + await this.weth.mint(owner.address, to18('1000000000')); + await this.weth.mint(user.address, to18('1000000000')); + await this.weth.mint(user2.address, to18('1000000000')); + await this.bean.connect(owner).approve(this.diamond.address, to18('1000000000')); + await this.weth.connect(owner).approve(this.diamond.address, to18('1000000000')); + await this.weth.connect(user).approve(this.diamond.address, to18('1000000000')); + await this.weth.connect(user2).approve(this.diamond.address, to18('1000000000')); + + this.well = await deployBasin(true, undefined, false, true) + this.wellToken = await ethers.getContractAt("IERC20", this.well.address) + await this.wellToken.connect(owner).approve(BEANSTALK, ethers.constants.MaxUint256) + await this.bean.connect(owner).approve(BEANSTALK, ethers.constants.MaxUint256) + + await setEthUsdPrice('999.998018') + await setEthUsdcPrice('1000') + + console.log(`Well Address: ${this.well.address}`) - await this.usdc.mint(owner.address, to18('1000000000')); - await this.usdc.mint(user.address, to6('1000')); - await this.usdc.mint(user2.address, to6('1000')); - await this.usdc.connect(owner).approve(this.diamond.address, to18('1000000000')); - await this.usdc.connect(user).approve(this.diamond.address, to18('1000000000')); - await this.usdc.connect(user2).approve(this.diamond.address, to18('1000000000')); }); beforeEach(async function () { @@ -69,7 +84,7 @@ describe('Fertilize', function () { }); it('reverts if early Season', async function () { - await expect(this.fertilizer.connect(owner).addFertilizerOwner('1000', '1', '0')).to.be.revertedWith('SafeMath: subtraction overflow') + await expect(this.fertilizer.connect(owner).addFertilizerOwner('1', '1', '0')).to.be.revertedWith('SafeMath: subtraction overflow') }) describe("Get Humidity", async function () { @@ -110,7 +125,7 @@ describe('Fertilize', function () { describe('Add Fertilizer', async function () { describe('1 fertilizer', async function () { beforeEach(async function () { - this.result = await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') + this.result = await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') }) it("updates totals", async function () { @@ -124,15 +139,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('2')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('1866180825834066049') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('29438342344636187') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('1')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(lpBeansForUsdc('1')) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.001')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(lpBeansForUsdc('1')) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('2')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('1866180825834066049') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -151,8 +166,8 @@ describe('Fertilize', function () { describe('1 fertilizer twice', async function () { beforeEach(async function () { - await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') this.depositedBeans = beansForUsdc('1').add(beansForUsdc('1')) }) @@ -166,15 +181,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('3.999999')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('3732361651668132099') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('58876684689272374') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('2')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(lpBeansForUsdc('2')) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.002')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(lpBeansForUsdc('2')) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('3.999999')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('3732361651668132099') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -184,8 +199,8 @@ describe('Fertilize', function () { describe('2 fertilizers', async function () { beforeEach(async function () { - await this.fertilizer.connect(owner).addFertilizerOwner('0', '5', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.005'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') this.lpBeans = lpBeansForUsdc('5').add(lpBeansForUsdc('1')) }) @@ -200,15 +215,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('11.999999')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('11197084955004396299') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('176630054067817122') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('6')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.006')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('11.999999')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('11197084955004396299') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -216,18 +231,27 @@ describe('Fertilize', function () { expect(await this.fertilizer.getFertilizer(to6('6'))).to.be.equal('5') }) }) + + describe('Too much Fertilizer', async function () { + it("reverts", async function () { + expect( + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('1'), '0') + ).to.be.revertedWith("Fertilizer: No more fertilizer available") + }) + + }) }) describe('Sort fertilizer seasons', async function () { beforeEach(async function () { - await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('6374', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('6274', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('9000', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('6174', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('6374', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('6274', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('9000', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('6174', to18('0.001'), '0') await this.season.rewardToFertilizerE(to6('2.5')) - await this.fertilizer.connect(owner).addFertilizerOwner('7000', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('0', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('7000', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.001'), '0') }) it('properly sorts fertilizer', async function () { @@ -251,7 +275,7 @@ describe('Fertilize', function () { describe('1 mint', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100') }) @@ -266,15 +290,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('200')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('186618082583406604989') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('2943834234463618707') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('100')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.1')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('200')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('186618082583406604989') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -297,8 +321,8 @@ describe('Fertilize', function () { describe('2 mints', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('50', '0', EXTERNAL) - this.result = await this.fertilizer.connect(user).mintFertilizer('50', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100'); }) @@ -313,15 +337,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal('199999999') // Rounds down - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('186618082583406604989') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('2943834234463618707') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('100')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.1')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal('199999999') // Rounds down - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('186618082583406604989') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -344,10 +368,10 @@ describe('Fertilize', function () { describe("2 mint with season in between", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100').add(lpBeansForUsdc('100')) }) @@ -363,15 +387,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('450')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('373236165166813209979') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('5887668468927237414') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('200')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.2')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('400')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('373236165166813209979') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -399,10 +423,10 @@ describe('Fertilize', function () { describe("2 mint with same id", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6174') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100').add(lpBeansForUsdc('100')) }) @@ -418,15 +442,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('450')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('373236165166813209979') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('5887668468927237414') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('200')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.2')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('400')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('373236165166813209979') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -453,11 +477,11 @@ describe('Fertilize', function () { describe("2 mint with same id and claim", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6174') await this.fertilizer.connect(user).claimFertilized([to6('3.5')], INTERNAL) - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) }) it('updates claims fertilized Beans', async function () { @@ -469,7 +493,7 @@ describe('Fertilize', function () { describe("Fertilize", async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) }) it('gets fertilizable', async function () { @@ -557,7 +581,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) @@ -586,7 +610,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) @@ -615,7 +639,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('200')) @@ -644,7 +668,7 @@ describe('Fertilize', function () { describe("Transfer", async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) }) describe("no fertilized", async function () { @@ -708,7 +732,7 @@ describe('Fertilize', function () { describe("Both some Beans", async function () { beforeEach(async function() { - this.result = await this.fertilizer.connect(user2).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('100')) await this.fert.connect(user).safeTransferFrom(user.address, user2.address, to6('2.5'), '50', ethers.constants.HashZero) }) @@ -735,7 +759,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) await this.fert.connect(user).safeBatchTransferFrom(user.address, user2.address, [to6('2.5'), to6('3.5')], ['50', '50'], ethers.constants.HashZero) }) @@ -763,11 +787,11 @@ describe('Fertilize', function () { describe("Both some Beans", async function () { beforeEach(async function() { - this.result = await this.fertilizer.connect(user2).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('400')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) - this.result = await this.fertilizer.connect(user2).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('300')) await this.fert.connect(user).safeBatchTransferFrom(user.address, user2.address, [to6('2.5'), to6('3.5')], ['50', '50'], ethers.constants.HashZero) }) From f1efc24c35da1ad0b58a285d76a7e7aa04ea0ad1 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:50:44 -0400 Subject: [PATCH 03/96] Add migrate function --- protocol/contracts/beanstalk/barn/UnripeFacet.sol | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 6cd0b3f345..764b5c598e 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -54,6 +54,7 @@ contract UnripeFacet is ReentrancyGuard { LibTransfer.From fromMode, LibTransfer.To toMode ) external payable nonReentrant returns (uint256 underlyingAmount) { + uint256 unripeSupply = IERC20(unripeToken).totalSupply(); amount = LibTransfer.burnToken(IBean(unripeToken), amount, msg.sender, fromMode); @@ -242,4 +243,16 @@ contract UnripeFacet is ReentrancyGuard { { return s.u[unripeToken].underlyingToken; } + + /////////////// UNDERLYING TOKEN MIGRATION ////////////////// + + function addMigratedUnderlying(address unripeToken, uint256 amount) external payable nonReentrant { + LibDiamond.enforceIsContractOwner(); + IERC20(s.u[unripeToken].underlyingToken).safeTransferFrom( + msg.sender, + address(this), + amount + ); + LibUnripe.incrementUnderlying(unripeToken, amount); + } } From 9efae4fc30a7c08e5802e2e2c71d1cc32a2c18a4 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:51:18 -0400 Subject: [PATCH 04/96] Use sync instead of add liquidity in Well convert --- .../contracts/libraries/Convert/LibWellConvert.sol | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/protocol/contracts/libraries/Convert/LibWellConvert.sol b/protocol/contracts/libraries/Convert/LibWellConvert.sol index a147e72438..a1cb7076b9 100644 --- a/protocol/contracts/libraries/Convert/LibWellConvert.sol +++ b/protocol/contracts/libraries/Convert/LibWellConvert.sol @@ -196,14 +196,10 @@ library LibWellConvert { require(maxBeans > 0, "Convert: P must be >= 1."); beansConverted = beans > maxBeans ? maxBeans : beans; IERC20[] memory tokens = IWell(well).tokens(); - uint256[] memory amounts = new uint256[](tokens.length); - amounts[beanIndex] = beansConverted; - C.bean().approve(well, beansConverted); - lp = IWell(well).addLiquidity( - amounts, - minLP, + C.bean().transfer(well, beans); + lp = IWell(well).sync( address(this), - block.timestamp + minLP ); } } From 5603486cb8dc5abee080c45836f897911cd7b530 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:51:56 -0400 Subject: [PATCH 05/96] Convert into/from Bean:Eth for Unripe assets --- .../libraries/Convert/LibUnripeConvert.sol | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/protocol/contracts/libraries/Convert/LibUnripeConvert.sol b/protocol/contracts/libraries/Convert/LibUnripeConvert.sol index 43824b8992..a493067178 100644 --- a/protocol/contracts/libraries/Convert/LibUnripeConvert.sol +++ b/protocol/contracts/libraries/Convert/LibUnripeConvert.sol @@ -5,7 +5,7 @@ pragma experimental ABIEncoderV2; import {C} from "contracts/C.sol"; import {IBean} from "contracts/interfaces/IBean.sol"; -import {LibCurveConvert} from "./LibCurveConvert.sol"; +import {LibWellConvert} from "./LibWellConvert.sol"; import {LibUnripe} from "../LibUnripe.sol"; import {LibConvertData} from "./LibConvertData.sol"; import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; @@ -39,10 +39,10 @@ library LibUnripeConvert { ( uint256 outUnderlyingAmount, uint256 inUnderlyingAmount - ) = LibCurveConvert.curveRemoveLPTowardsPeg( + ) = LibWellConvert._wellRemoveLiquidityTowardsPeg( LibUnripe.unripeToUnderlying(tokenIn, lp), minAmountOut, - C.CURVE_BEAN_METAPOOL + C.BEAN_ETH_WELL ); amountIn = LibUnripe.underlyingToUnripe(tokenIn, inUnderlyingAmount); @@ -78,10 +78,10 @@ library LibUnripeConvert { ( uint256 outUnderlyingAmount, uint256 inUnderlyingAmount - ) = LibCurveConvert.curveAddLiquidityTowardsPeg( + ) = LibWellConvert._wellAddLiquidityTowardsPeg( LibUnripe.unripeToUnderlying(tokenIn, beans), minAmountOut, - C.CURVE_BEAN_METAPOOL + C.BEAN_ETH_WELL ); amountIn = LibUnripe.underlyingToUnripe(tokenIn, inUnderlyingAmount); @@ -97,8 +97,8 @@ library LibUnripeConvert { } function beansToPeg() internal view returns (uint256 beans) { - uint256 underlyingBeans = LibCurveConvert.beansToPeg( - C.CURVE_BEAN_METAPOOL + uint256 underlyingBeans = LibWellConvert.beansToPeg( + C.BEAN_ETH_WELL ); beans = LibUnripe.underlyingToUnripe( C.UNRIPE_BEAN, @@ -107,8 +107,8 @@ library LibUnripeConvert { } function lpToPeg() internal view returns (uint256 lp) { - uint256 underlyingLP = LibCurveConvert.lpToPeg( - C.CURVE_BEAN_METAPOOL + uint256 underlyingLP = LibWellConvert.lpToPeg( + C.BEAN_ETH_WELL ); lp = LibUnripe.underlyingToUnripe(C.UNRIPE_LP, underlyingLP); } @@ -122,7 +122,7 @@ library LibUnripeConvert { C.UNRIPE_BEAN, amountIn ); - lp = LibCurveConvert.getLPAmountOut(C.CURVE_BEAN_METAPOOL, beans); + lp = LibWellConvert.getLPAmountOut(C.BEAN_ETH_WELL, beans); lp = LibUnripe .underlyingToUnripe(C.UNRIPE_LP, lp) .mul(LibUnripe.percentLPRecapped()) @@ -138,7 +138,7 @@ library LibUnripeConvert { C.UNRIPE_LP, amountIn ); - bean = LibCurveConvert.getBeanAmountOut(C.CURVE_BEAN_METAPOOL, lp); + bean = LibWellConvert.getBeanAmountOut(C.BEAN_ETH_WELL, lp); bean = LibUnripe .underlyingToUnripe(C.UNRIPE_BEAN, bean) .mul(LibUnripe.percentBeansRecapped()) From 4b024b62f75b427b0590c0a73a25f61ed77e30d3 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:53:42 -0400 Subject: [PATCH 06/96] Script and Helper function updates --- protocol/scripts/basin.js | 54 ++++++++++++++++-------------- protocol/scripts/impersonate.js | 14 ++++++-- protocol/test/EthUsdOracle.test.js | 34 +++---------------- protocol/test/WellBdv.test.js | 1 - protocol/test/WellConvert.test.js | 1 - protocol/utils/oracle.js | 38 +++++++++++++++++++++ 6 files changed, 82 insertions(+), 60 deletions(-) create mode 100644 protocol/utils/oracle.js diff --git a/protocol/scripts/basin.js b/protocol/scripts/basin.js index f98b7dfe98..6efb0dcfb6 100644 --- a/protocol/scripts/basin.js +++ b/protocol/scripts/basin.js @@ -37,15 +37,15 @@ async function deployBasinAndIntegrationBip(mock, bipAccount = undefined, basinA await bipBasinIntegration(mock, bipAccount); } -async function deployBasin(mock = true, accounts = undefined) { +async function deployBasin(mock = true, accounts = undefined, verbose = true, justDeploy = false) { - console.log("Deploying Basin...") + if (verbose) console.log("Deploying Basin...") let account = await getAccount(accounts, 'aquifer', AQUIFER_DEPLOYER); - const aquifer = await deployWellContractAtNonce('Aquifer', AQUIFER_DEPLOY_NONCE, [], account, true); + const aquifer = await deployWellContractAtNonce('Aquifer', AQUIFER_DEPLOY_NONCE, [], account, verbose); account = await getAccount(accounts, 'constantProduct2', CONSTANT_PRODUCT_2_DEPLOYER); - const constantProduct2 = await deployWellContractAtNonce('ConstantProduct2', CONSTANT_PRODUCT_2_DEPLOY_NONCE, [], account, true); + const constantProduct2 = await deployWellContractAtNonce('ConstantProduct2', CONSTANT_PRODUCT_2_DEPLOY_NONCE, [], account, verbose); account = await getAccount(accounts, 'multiFlowPump', MULTI_FLOW_PUMP_DEPLOYER); let multiFlowPump = await deployWellContractAtNonce('MultiFlowPump', MULTI_FLOW_PUMP_DEPLOY_NONCE, [ @@ -53,11 +53,11 @@ async function deployBasin(mock = true, accounts = undefined) { MULTI_FLOW_PUMP_MAX_PERCENT_DECREASE, MULTI_FLOW_PUMP_CAP_INTERVAL, MULTI_FLOW_PUMP_ALPHA - ], account, true); + ], account, verbose); account = await getAccount(accounts, 'wellImplementation', WELL_IMPLEMENTATION_DEPLOYER); const wellImplementation = await deployWellContractAtNonce('Well', WELL_IMPLEMENTATION_DEPLOY_NONCE, [], account, false); - console.log("Well Implementation Deployed at", wellImplementation.address); + if (verbose) console.log("Well Implementation Deployed at", wellImplementation.address); account = await getAccount(accounts, 'well', WELL_DEPLOYER); const immutableData = encodeWellImmutableData( @@ -88,11 +88,13 @@ async function deployBasin(mock = true, accounts = undefined) { await wellTxn.wait(); - console.log("Bean:Eth Well Deployed at:", well.address); + if (justDeploy) return well; - console.log(""); + if (verbose) console.log("Bean:Eth Well Deployed at:", well.address); - console.log("Adding Liquidity to Well...") + if (verbose) console.log(""); + + if (verbose) console.log("Adding Liquidity to Well...") account = await getAccount(accounts, 'addLiquidity', ADD_LIQUIDITY_ADDRESS); @@ -102,51 +104,51 @@ async function deployBasin(mock = true, accounts = undefined) { const ethUsdChainlinkAggregator = await ethers.getContractAt('MockChainlinkAggregator', ETH_USD_CHAINLINK_AGGREGATOR) const beanEthPrice = (await ethUsdChainlinkAggregator.latestRoundData()).answer; - console.log("Bean:Eth Price:", beanEthPrice.toString()); + if (verbose) console.log("Bean:Eth Price:", beanEthPrice.toString()); const amounts = [ toBN(INITIAL_BEAN_LIQUIDITY), toBN(INITIAL_BEAN_LIQUIDITY).mul(toX('1', 20)).div(beanEthPrice) ] - console.log("Bean Amount:", amounts[0].toString()); - console.log("Eth Amount:", amounts[1].toString()); + if (verbose) console.log("Bean Amount:", amounts[0].toString()); + if (verbose) console.log("Eth Amount:", amounts[1].toString()); - console.log(account.address) + if (verbose) console.log(account.address) - console.log("Approving.."); + if (verbose) onsole.log("Approving.."); await bean.connect(account).approve(well.address, amounts[0]); await weth.connect(account).approve(well.address, amounts[1]); - console.log("Wrapping Eth.."); + if (verbose) console.log("Wrapping Eth.."); await weth.connect(account).deposit({ value: amounts[1] }); - console.log('Adding Liquidity..') + if (verbose) console.log('Adding Liquidity..') const lpAmountOut = well.getAddLiquidityOut(amounts); let txn = await well.connect(account).addLiquidity(amounts, lpAmountOut, account.address, ethers.constants.MaxUint256); await txn.wait(); txn = await well.connect(account).addLiquidity([toBN('0'), toBN('0')], '0', account.address, ethers.constants.MaxUint256); await txn.wait(); - console.log('') + if (verbose) console.log('') const reserves = await well.getReserves(); - console.log("Well Statistics:") - console.log("Bean Reserve:", reserves[0].toString()); - console.log("Eth Reserve:", reserves[1].toString()); - console.log("LP Token Total Supply:", (await well.totalSupply()).toString()); + if (verbose) console.log("Well Statistics:") + if (verbose) console.log("Bean Reserve:", reserves[0].toString()); + if (verbose) console.log("Eth Reserve:", reserves[1].toString()); + if (verbose) console.log("LP Token Total Supply:", (await well.totalSupply()).toString()); - console.log('') + if (verbose) console.log('') - console.log("Pump Statistics:") + if (verbose) console.log("Pump Statistics:") const instantaneousReserves = await multiFlowPump.readInstantaneousReserves( well.address, "0x" ); - console.log("Instantaneous Bean Reserve:", instantaneousReserves[0].toString()); - console.log("Instantaneous WETH Reserve:", instantaneousReserves[1].toString()); + if (verbose) console.log("Instantaneous Bean Reserve:", instantaneousReserves[0].toString()); + if (verbose) console.log("Instantaneous WETH Reserve:", instantaneousReserves[1].toString()); - console.log('') + if (verbose) console.log('') } async function getAccount(accounts, key, mockAddress) { diff --git a/protocol/scripts/impersonate.js b/protocol/scripts/impersonate.js index f603ed405e..261a738ba9 100644 --- a/protocol/scripts/impersonate.js +++ b/protocol/scripts/impersonate.js @@ -281,6 +281,17 @@ async function beanEthWell() { ]); } +async function impersonateContract(contractName, deployAddress) { + contract = await (await ethers.getContractFactory(contractName)).deploy() + await contract.deployed() + const bytecode = await ethers.provider.getCode(contract.address) + await network.provider.send("hardhat_setCode", [ + deployAddress, + bytecode, + ]); + return await ethers.getContractAt(contractName, deployAddress) +} + async function ethUsdChainlinkAggregator() { let chainlinkAggregatorJson = fs.readFileSync(`./artifacts/contracts/mocks/chainlink/MockChainlinkAggregator.sol/MockChainlinkAggregator.json`); @@ -292,8 +303,6 @@ async function ethUsdChainlinkAggregator() { await ethUsdChainlinkAggregator.setDecimals(6) } - - exports.impersonateRouter = router exports.impersonateBean = bean exports.impersonateCurve = curve @@ -311,3 +320,4 @@ exports.impersonateEthUsdtUniswap = ethUsdtUniswap exports.impersonateBeanstalk = impersonateBeanstalk exports.impersonateEthUsdChainlinkAggregator = ethUsdChainlinkAggregator exports.impersonateBeanEthWell = beanEthWell +exports.impersonateContract = impersonateContract diff --git a/protocol/test/EthUsdOracle.test.js b/protocol/test/EthUsdOracle.test.js index 70018aef69..7413062d7d 100644 --- a/protocol/test/EthUsdOracle.test.js +++ b/protocol/test/EthUsdOracle.test.js @@ -1,35 +1,14 @@ const { expect } = require('chai'); const { deploy } = require('../scripts/deploy.js'); const { getAltBeanstalk, getBean } = require('../utils/contracts.js'); -const { ETH_USDC_UNISWAP_V3, ETH_USDT_UNISWAP_V3, WETH, ETH_USD_CHAINLINK_AGGREGATOR } = require('./utils/constants.js'); +const { ETH_USDC_UNISWAP_V3, ETH_USDT_UNISWAP_V3, WETH } = require('./utils/constants.js'); const { to6, to18 } = require('./utils/helpers.js'); const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot.js"); const { toBN } = require('../utils/helpers.js'); +const { setEthUsdcPrice, setEthUsdPrice, setEthUsdtPrice, setOracleFailure } = require('../utils/oracle.js'); let user, user2, owner; -let ethUsdcUniswapPool, ethUsdtUniswapPool, ethUsdChainlinkAggregator; - -async function setEthUsdcPrice(price) { - await ethUsdcUniswapPool.setOraclePrice(to6(price), 18); -} - -async function setEthUsdPrice(price) { - const block = await ethers.provider.getBlock("latest"); - await ethUsdChainlinkAggregator.addRound(to6(price), block.timestamp, block.timestamp, '1') -} - -async function setEthUsdtPrice(price) { - await ethUsdtUniswapPool.setOraclePrice(to18('1').div(toBN('1').add(price)), 6); -} - -async function printPrices() { - console.log(`CUSD Price: ${await season.getChainlinkEthUsdPrice()}`) - console.log(`USDT Price: ${await season.getEthUsdtPrice()}`) - console.log(`USDC Price: ${await season.getEthUsdcPrice()}`) - -} - async function setToSecondsAfterHour(seconds = 0) { const lastTimestamp = (await ethers.provider.getBlock('latest')).timestamp; const hourTimestamp = parseInt(lastTimestamp/3600 + 1) * 3600 + seconds @@ -53,11 +32,6 @@ describe('USD Oracle', function () { await setToSecondsAfterHour(0) await owner.sendTransaction({to: user.address, value: 0}) - ethUsdtUniswapPool = await ethers.getContractAt('MockUniswapV3Pool', ETH_USDT_UNISWAP_V3); - ethUsdChainlinkAggregator = await ethers.getContractAt('MockChainlinkAggregator', ETH_USD_CHAINLINK_AGGREGATOR) - await ethUsdChainlinkAggregator.setDecimals(6) - ethUsdcUniswapPool = await ethers.getContractAt('MockUniswapV3Pool', ETH_USDC_UNISWAP_V3); - await setEthUsdPrice('10000') await setEthUsdcPrice('10000') await setEthUsdtPrice('10000') @@ -171,13 +145,13 @@ describe('USD Oracle', function () { describe("Handles Uniswap Oracle Failure", async function () { it ('succeeds when ETH/USDT call fails', async function () { - await ethUsdtUniswapPool.setOracleFailure(true) + await setOracleFailure(true, ETH_USDT_UNISWAP_V3) await setEthUsdcPrice('10050') await checkPriceWithError('10025') }) it ('succeeds when ETH/USDC call fails', async function () { - await ethUsdcUniswapPool.setOracleFailure(true) + await setOracleFailure(true, ETH_USDC_UNISWAP_V3) await checkPriceWithError('10000') }) }) diff --git a/protocol/test/WellBdv.test.js b/protocol/test/WellBdv.test.js index c0186b91f4..69a45885f8 100644 --- a/protocol/test/WellBdv.test.js +++ b/protocol/test/WellBdv.test.js @@ -34,7 +34,6 @@ describe('Well BDV', function () { await this.well.setTokens([BEAN, WETH]) this.pump.setInstantaneousReserves([to18('1'), to18('1')]) await whitelistWell(this.well.address, '10000', to6('4')) - }); beforeEach(async function () { diff --git a/protocol/test/WellConvert.test.js b/protocol/test/WellConvert.test.js index a79f2935e4..19764200d3 100644 --- a/protocol/test/WellConvert.test.js +++ b/protocol/test/WellConvert.test.js @@ -31,7 +31,6 @@ describe('Well Convert', function () { await this.wellToken.connect(owner).approve(this.beanstalk.address, ethers.constants.MaxUint256) await this.bean.connect(owner).approve(this.beanstalk.address, ethers.constants.MaxUint256) - await setEthUsdPrice('999.998018') await setEthUsdcPrice('1000') await setEthUsdtPrice('1000') diff --git a/protocol/utils/oracle.js b/protocol/utils/oracle.js new file mode 100644 index 0000000000..25e8f75fa9 --- /dev/null +++ b/protocol/utils/oracle.js @@ -0,0 +1,38 @@ +const { ETH_USDC_UNISWAP_V3, ETH_USD_CHAINLINK_AGGREGATOR, ETH_USDT_UNISWAP_V3, BEANSTALK } = require("../test/utils/constants"); +const { to18, to6 } = require("../test/utils/helpers"); +const { toBN } = require("./helpers"); + +async function setEthUsdcPrice(price) { + const ethUsdcUniswapPool = await ethers.getContractAt('MockUniswapV3Pool', ETH_USDC_UNISWAP_V3); + await ethUsdcUniswapPool.setOraclePrice(to6(price), 18); +} + +async function setEthUsdPrice(price) { + const ethUsdChainlinkAggregator = await ethers.getContractAt('MockChainlinkAggregator', ETH_USD_CHAINLINK_AGGREGATOR) + const block = await ethers.provider.getBlock("latest"); + await ethUsdChainlinkAggregator.addRound(to6(price), block.timestamp, block.timestamp, '1') +} + +async function setEthUsdtPrice(price) { + const ethUsdtUniswapPool = await ethers.getContractAt('MockUniswapV3Pool', ETH_USDT_UNISWAP_V3); + await ethUsdtUniswapPool.setOraclePrice(to18('1').div(toBN('1').add(price)), 6); +} + +async function printPrices() { + const season = await ethers.getContractAt('MockSeasonFacet', BEANSTALK); + console.log(`CUSD Price: ${await season.getChainlinkEthUsdPrice()}`) + console.log(`USDT Price: ${await season.getEthUsdtPrice()}`) + console.log(`USDC Price: ${await season.getEthUsdcPrice()}`) + console.log(`USD Price: ${await season.getEthUsdPrice()}`) +} + +async function setOracleFailure(bool, poolAddress) { + const pool = await ethers.getContractAt('MockUniswapV3Pool', poolAddress); + await pool.setOracleFailure(bool); +} + +exports.setEthUsdcPrice = setEthUsdcPrice; +exports.setEthUsdPrice = setEthUsdPrice; +exports.setEthUsdtPrice = setEthUsdtPrice; +exports.printPrices = printPrices; +exports.setOracleFailure = setOracleFailure; \ No newline at end of file From 054e30500002b79c6d000ea62896fd6571195bad Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:54:07 -0400 Subject: [PATCH 07/96] Update Unripe BDV Function --- .../contracts/beanstalk/silo/BDVFacet.sol | 2 +- protocol/test/bdv.test.js | 64 +++++++++---------- 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/protocol/contracts/beanstalk/silo/BDVFacet.sol b/protocol/contracts/beanstalk/silo/BDVFacet.sol index 466bc615ab..84334341af 100644 --- a/protocol/contracts/beanstalk/silo/BDVFacet.sol +++ b/protocol/contracts/beanstalk/silo/BDVFacet.sol @@ -37,7 +37,7 @@ contract BDVFacet { */ function unripeLPToBDV(uint256 amount) public view returns (uint256) { amount = LibUnripe.unripeToUnderlying(C.UNRIPE_LP, amount); - amount = LibBeanMetaCurve.bdv(amount); + amount = LibWellBdv.bdv(C.BEAN_ETH_WELL, amount); return amount; } diff --git a/protocol/test/bdv.test.js b/protocol/test/bdv.test.js index 67c9978578..319bb4b289 100644 --- a/protocol/test/bdv.test.js +++ b/protocol/test/bdv.test.js @@ -1,8 +1,11 @@ const { expect } = require('chai'); const { deploy } = require('../scripts/deploy.js') const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); -const { BEAN, THREE_POOL, BEAN_3_CURVE, UNRIPE_LP, UNRIPE_BEAN, ZERO_ADDRESS } = require('./utils/constants'); -const { to18, to6 } = require('./utils/helpers.js') +const { BEAN, THREE_POOL, BEAN_3_CURVE, UNRIPE_LP, UNRIPE_BEAN, ZERO_ADDRESS, WETH, BEAN_ETH_WELL } = require('./utils/constants'); +const { to18, to6 } = require('./utils/helpers.js'); +const { deployMockPump, getWellContractFactory, whitelistWell } = require('../utils/well.js'); +const { impersonateContract } = require('../scripts/impersonate.js'); +const { toBN } = require('../utils/helpers.js'); let user,user2,owner; let userAddress, ownerAddress, user2Address; const ZERO_BYTES = ethers.utils.formatBytes32String('0x0') @@ -11,6 +14,7 @@ let snapshotId; describe('BDV', function () { before(async function () { + [owner,user,user2] = await ethers.getSigners(); userAddress = user.address; user2Address = user2.address; @@ -22,34 +26,26 @@ describe('BDV', function () { this.silo = await ethers.getContractAt('MockSiloFacet', this.diamond.address) this.convert = await ethers.getContractAt('ConvertFacet', this.diamond.address) this.bean = await ethers.getContractAt('MockToken', BEAN); + this.bdv = await ethers.getContractAt('BDVFacet', this.diamond.address) - this.siloToken = await ethers.getContractFactory("MockToken"); - this.siloToken = await this.siloToken.deploy("Silo", "SILO") - await this.siloToken.deployed() - - await this.silo.mockWhitelistToken( - this.siloToken.address, - this.silo.interface.getSighash("mockBDV(uint256 amount)"), - '10000', - 1e6 //aka "1 seed" - ); + this.well = await impersonateContract('MockSetComponentsWell', BEAN_ETH_WELL) await this.season.siloSunrise(0); await this.bean.mint(userAddress, '1000000000'); await this.bean.mint(ownerAddress, '1000000000'); - await this.siloToken.connect(user).approve(this.silo.address, '100000000000'); + await this.well.connect(user).approve(this.silo.address, '100000000000'); await this.bean.connect(user).approve(this.silo.address, '100000000000'); await this.bean.connect(owner).approve(this.silo.address, '100000000000'); - await this.siloToken.mint(userAddress, '10000'); - await this.siloToken.mint(ownerAddress, to18('1000')); - await this.siloToken.approve(this.silo.address, to18('1000')); + await this.well.mint(userAddress, '10000'); + await this.well.mint(ownerAddress, to18('1000')); + await this.well.approve(this.silo.address, to18('1000')); this.unripe = await ethers.getContractAt('MockUnripeFacet', this.silo.address) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) await this.unripeLP.connect(user).mint(userAddress, to18('10000')) await this.unripeLP.connect(user).approve(this.silo.address, to18('10000')) - await this.unripe.addUnripeToken(UNRIPE_LP, this.siloToken.address, ZERO_BYTES) + await this.unripe.addUnripeToken(UNRIPE_LP, this.well.address, ZERO_BYTES) await this.unripe.connect(owner).addUnderlying( UNRIPE_LP, to18('1000') @@ -114,29 +110,29 @@ describe('BDV', function () { describe("Unripe LP BDV", async function () { before(async function () { - this.threePool = await ethers.getContractAt('Mock3Curve', THREE_POOL); - await this.threePool.set_virtual_price(to18('1')); - this.beanThreeCurve = await ethers.getContractAt('MockMeta3Curve', BEAN_3_CURVE); - await this.beanThreeCurve.set_supply(to18('2000000')); - await this.beanThreeCurve.set_A_precise('1000'); - await this.beanThreeCurve.set_virtual_price(to18('1')); - await this.beanThreeCurve.set_balances([ - to6('1000000'), - to18('1000000') - ]); - await this.beanThreeCurve.set_balances([ - to6('1200000'), - to18('1000000') - ]); + this.pump = await deployMockPump() + + this.wellFunction = await (await getWellContractFactory('ConstantProduct2')).deploy() + await this.wellFunction.deployed() + + await this.well.setPumps([[this.pump.address, '0x']]) + await this.well.setWellFunction([this.wellFunction.address, '0x']) + await this.well.setTokens([BEAN, WETH]) + this.pump.setInstantaneousReserves([to18('1'), to18('1')]) + await whitelistWell(this.well.address, '10000', to6('4')) }); it("properly checks bdv", async function () { - expect(await this.silo.bdv(UNRIPE_LP, to18('2000'))).to.equal(to6('200')); + const wellBdv = await this.silo.bdv(this.well.address, to18('200')) + expect(await this.bdv.unripeLPToBDV(to18('2000'))).to.eq(wellBdv); + expect(await this.silo.bdv(UNRIPE_LP, to18('2000'))).to.equal(wellBdv); }) it("properly checks bdv", async function () { - await this.threePool.set_virtual_price(to18('1.02')); - expect(await this.silo.bdv(UNRIPE_LP, to18('20'))).to.equal('1998191'); + this.pump.setInstantaneousReserves([to18('1.02'), to18('1')]) + const wellBdv = await this.silo.bdv(this.well.address, to18('2')) + expect(await this.bdv.unripeLPToBDV(to18('20'))).to.equal(wellBdv); + expect(await this.silo.bdv(UNRIPE_LP, to18('20'))).to.equal(wellBdv); }) }) From 991785618f0e29539cb9c804ec499dc3b2036520 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:54:20 -0400 Subject: [PATCH 08/96] Add migration init script --- .../init/InitMigrateUnripeBean3CrvToEth.sol | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol diff --git a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol new file mode 100644 index 0000000000..6ea7ee6be5 --- /dev/null +++ b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol @@ -0,0 +1,31 @@ +/* + SPDX-License-Identifier: MIT +*/ + +pragma solidity =0.7.6; +pragma experimental ABIEncoderV2; + +import {AppStorage} from "contracts/beanstalk/AppStorage.sol"; +import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import {C} from "contracts/C.sol"; +import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; +import {LibUnripe} from "contracts/libraries/LibUnripe.sol"; + +/** + * Initializes the Migration of the Unripe LP underlying tokens from Bean:3Crv to Bean:Eth. + */ +contract InitMigrateUnripeBean3CrvToEth { + using SafeERC20 for IERC20; + + AppStorage internal s; + + function init() external { + uint256 balanceOfUnderlying = s.u[C.UNRIPE_LP].balanceOfUnderlying; + IERC20(s.u[C.UNRIPE_LP].underlyingToken).safeTransfer( + LibDiamond.diamondStorage().contractOwner, + balanceOfUnderlying + ); + LibUnripe.decrementUnderlying(C.UNRIPE_LP, balanceOfUnderlying); + s.u[C.UNRIPE_LP].underlyingToken = C.BEAN_ETH_WELL; + } +} \ No newline at end of file From 37343e214538e0856ee2568d308b878a800e2530 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 13:04:55 -0400 Subject: [PATCH 09/96] fix build --- .../contracts/beanstalk/barn/FertilizerFacet.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index fdcc4179f6..ec0737c7de 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -49,9 +49,9 @@ contract FertilizerFacet { * Can be used to help calculate `minFertilizerOut` in `mintFertilizer` */ function getMintFertilizerOut( - uint128 wethAmountIn + uint256 wethAmountIn ) external view returns (uint256 fertilizerAmountOut) { - fertilizerAmountOut = amount.mul( + fertilizerAmountOut = wethAmountIn.mul( LibEthUsdOracle.getEthUsdPrice() ).div(1e24); } @@ -71,15 +71,15 @@ contract FertilizerFacet { LibTransfer.From mode ) external payable returns (uint256 fertilizerAmountOut) { - amount = LibTransfer.receiveToken( + wethAmountIn = LibTransfer.receiveToken( IERC20(C.WETH), - uint256(amount), + uint256(wethAmountIn), msg.sender, mode ); // return value <= amount, so downcasting is safe. // Convert from Ether amount with 18 decimals to USD amount with 0 decimals. - fertilizerAmountOut = amount.mul( + fertilizerAmountOut = wethAmountIn.mul( LibEthUsdOracle.getEthUsdPrice() ).div(1e24); @@ -90,7 +90,7 @@ contract FertilizerFacet { uint128 id = LibFertilizer.addFertilizer( uint128(s.season.current), - amount, + wethAmountIn, fertilizerAmountOut, minLP ); From adc02b8621ff44ce2b552bfb879951db5d9df8a6 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 14:56:19 -0400 Subject: [PATCH 10/96] rename init, update tests/scripts --- ...=> InitMigrateUnripeBean3CrvToBeanEth.sol} | 2 +- protocol/scripts/bips.js | 26 +++++++ protocol/scripts/impersonate.js | 14 +--- protocol/test/Fertilizer.test.js | 38 +++++----- protocol/test/SiloEnroot.test.js | 23 +++---- protocol/test/Stem.test.js | 2 +- protocol/test/beanstalkPrice.test.js | 2 +- protocol/utils/well.js | 69 ++++++++++++------- 8 files changed, 104 insertions(+), 72 deletions(-) rename protocol/contracts/beanstalk/init/{InitMigrateUnripeBean3CrvToEth.sol => InitMigrateUnripeBean3CrvToBeanEth.sol} (95%) diff --git a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol similarity index 95% rename from protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol rename to protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol index 6ea7ee6be5..8b1d77b910 100644 --- a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol +++ b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol @@ -14,7 +14,7 @@ import {LibUnripe} from "contracts/libraries/LibUnripe.sol"; /** * Initializes the Migration of the Unripe LP underlying tokens from Bean:3Crv to Bean:Eth. */ -contract InitMigrateUnripeBean3CrvToEth { +contract InitMigrateUnripeBean3CrvToBeanEth { using SafeERC20 for IERC20; AppStorage internal s; diff --git a/protocol/scripts/bips.js b/protocol/scripts/bips.js index 4d9faefdd2..c40351a4a1 100644 --- a/protocol/scripts/bips.js +++ b/protocol/scripts/bips.js @@ -144,6 +144,31 @@ async function bip34(mock = true, account = undefined) { verify: false }); } +async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefined, verbose = true) { + if (account == undefined) { + account = await impersonateBeanstalkOwner(); + await mintEth(account.address); + } + + await upgradeWithNewFacets({ + diamondAddress: BEANSTALK, + facetNames: [ + "UnripeFacet", + "FertilizerFacet", + "BDVFacet", + "ConvertFacet", + "ConvertGettersFacet" + ], + initFacetName: "InitMigrateUnripeBean3CrvToBeanEth", + selectorsToRemove: [ '0x0bfca7e3' ], + bip: false, + object: !mock, + verbose: true, + account: account, + verify: false + }); + +} exports.bip29 = bip29 exports.bip30 = bip30 @@ -151,3 +176,4 @@ exports.bip34 = bip34 exports.bipNewSilo = bipNewSilo exports.bipBasinIntegration = bipBasinIntegration exports.mockBeanstalkAdmin = mockBeanstalkAdmin +exports.bipMigrateUnripeBean3CrvToBeanEth = bipMigrateUnripeBean3CrvToBeanEth diff --git a/protocol/scripts/impersonate.js b/protocol/scripts/impersonate.js index 261a738ba9..93aed6ab23 100644 --- a/protocol/scripts/impersonate.js +++ b/protocol/scripts/impersonate.js @@ -24,10 +24,8 @@ const { ETH_USDC_UNISWAP_V3, ETH_USDT_UNISWAP_V3, USDT, - ETH_USD_CHAINLINK_AGGREGATOR, - BEAN_ETH_WELL + ETH_USD_CHAINLINK_AGGREGATOR } = require('../test/utils/constants'); -const { deployWell } = require('../utils/well.js'); const { impersonateSigner, mintEth } = require('../utils'); const { getSigner } = '../utils' @@ -272,15 +270,6 @@ async function ethUsdtUniswap() { ]); } -async function beanEthWell() { - const well = await deployWell([BEAN, WETH]); - const bytecode = await ethers.provider.getCode(well.address) - await network.provider.send("hardhat_setCode", [ - BEAN_ETH_WELL, - bytecode, - ]); -} - async function impersonateContract(contractName, deployAddress) { contract = await (await ethers.getContractFactory(contractName)).deploy() await contract.deployed() @@ -319,5 +308,4 @@ exports.impersonateEthUsdcUniswap = ethUsdcUniswap exports.impersonateEthUsdtUniswap = ethUsdtUniswap exports.impersonateBeanstalk = impersonateBeanstalk exports.impersonateEthUsdChainlinkAggregator = ethUsdChainlinkAggregator -exports.impersonateBeanEthWell = beanEthWell exports.impersonateContract = impersonateContract diff --git a/protocol/test/Fertilizer.test.js b/protocol/test/Fertilizer.test.js index 4519aef102..adab06a69c 100644 --- a/protocol/test/Fertilizer.test.js +++ b/protocol/test/Fertilizer.test.js @@ -275,7 +275,7 @@ describe('Fertilize', function () { describe('1 mint', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100') }) @@ -321,8 +321,8 @@ describe('Fertilize', function () { describe('2 mints', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', EXTERNAL) - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100'); }) @@ -368,10 +368,10 @@ describe('Fertilize', function () { describe("2 mint with season in between", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100').add(lpBeansForUsdc('100')) }) @@ -423,10 +423,10 @@ describe('Fertilize', function () { describe("2 mint with same id", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6174') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100').add(lpBeansForUsdc('100')) }) @@ -477,11 +477,11 @@ describe('Fertilize', function () { describe("2 mint with same id and claim", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6174') await this.fertilizer.connect(user).claimFertilized([to6('3.5')], INTERNAL) - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) }) it('updates claims fertilized Beans', async function () { @@ -493,7 +493,7 @@ describe('Fertilize', function () { describe("Fertilize", async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) }) it('gets fertilizable', async function () { @@ -581,7 +581,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) @@ -610,7 +610,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) @@ -639,7 +639,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('200')) @@ -668,7 +668,7 @@ describe('Fertilize', function () { describe("Transfer", async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) }) describe("no fertilized", async function () { @@ -732,7 +732,7 @@ describe('Fertilize', function () { describe("Both some Beans", async function () { beforeEach(async function() { - this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('100')) await this.fert.connect(user).safeTransferFrom(user.address, user2.address, to6('2.5'), '50', ethers.constants.HashZero) }) @@ -759,7 +759,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) await this.fert.connect(user).safeBatchTransferFrom(user.address, user2.address, [to6('2.5'), to6('3.5')], ['50', '50'], ethers.constants.HashZero) }) @@ -787,11 +787,11 @@ describe('Fertilize', function () { describe("Both some Beans", async function () { beforeEach(async function() { - this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('400')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) - this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('300')) await this.fert.connect(user).safeBatchTransferFrom(user.address, user2.address, [to6('2.5'), to6('3.5')], ['50', '50'], ethers.constants.HashZero) }) diff --git a/protocol/test/SiloEnroot.test.js b/protocol/test/SiloEnroot.test.js index dd3a549217..dbe618ce68 100644 --- a/protocol/test/SiloEnroot.test.js +++ b/protocol/test/SiloEnroot.test.js @@ -1,11 +1,11 @@ const { expect } = require("chai"); const { deploy } = require("../scripts/deploy.js"); -const { readPrune, toBN, signSiloDepositTokenPermit, signSiloDepositTokensPermit, getBean } = require("../utils"); -const { getAltBeanstalk } = require("../utils/contracts.js"); -const { EXTERNAL, INTERNAL, INTERNAL_EXTERNAL, INTERNAL_TOLERANT } = require("./utils/balances.js"); -const { BEAN, THREE_POOL, BEAN_3_CURVE, UNRIPE_LP, UNRIPE_BEAN, THREE_CURVE } = require("./utils/constants"); -const { to18, to6, toStalk, toBean } = require("./utils/helpers.js"); +const { readPrune, toBN, } = require("../utils"); +const { EXTERNAL } = require("./utils/balances.js"); +const { BEAN, BEAN_3_CURVE, UNRIPE_LP, UNRIPE_BEAN, THREE_CURVE, BEAN_ETH_WELL, WETH } = require("./utils/constants"); +const { to18, to6, toStalk } = require("./utils/helpers.js"); const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); +const { impersonateMockWell } = require("../utils/well.js"); const ZERO_BYTES = ethers.utils.formatBytes32String("0x0"); let user, user2, owner; @@ -47,13 +47,8 @@ describe("Silo Enroot", function () { await this.season.teleportSunrise(ENROOT_FIX_SEASON) - this.threeCurve = await ethers.getContractAt('MockToken', THREE_CURVE); - this.beanMetapool = await ethers.getContractAt('IMockCurvePool', BEAN_3_CURVE); - await this.beanMetapool.set_supply(ethers.utils.parseUnits('2000000', 6)); - await this.beanMetapool.set_balances([ - ethers.utils.parseUnits('1000000',6), - ethers.utils.parseEther('1000000') - ]); + const [well, pump, wellFunction] = await impersonateMockWell(pumpBalances = [to6('10000'), to18('10')]); + this.well = well; this.pump = pump; this.wellFunction = wellFunction; const SiloToken = await ethers.getContractFactory("MockToken"); this.siloToken = await SiloToken.deploy("Silo", "SILO"); @@ -265,12 +260,12 @@ describe("Silo Enroot", function () { it('properly updates the total balances', async function () { expect(await this.silo.getTotalDeposited(UNRIPE_LP)).to.eq(to6('20')); - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('3.7120352584')); + expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('234.7639163944')); expect(await this.silo.balanceOfSeeds(userAddress)).to.eq('0'); }); it('properly updates the user balance', async function () { - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('3.7120352584')); + expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('234.7639163944')); expect(await this.silo.balanceOfSeeds(userAddress)).to.eq('0'); }); diff --git a/protocol/test/Stem.test.js b/protocol/test/Stem.test.js index cda2fb03c1..381975a3c7 100644 --- a/protocol/test/Stem.test.js +++ b/protocol/test/Stem.test.js @@ -34,7 +34,7 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { console.log('forking error in Silo V3: Grown Stalk Per Bdv:'); console.log(error); return - }4 + } const signer = await impersonateBeanstalkOwner() await mintEth(signer.address); diff --git a/protocol/test/beanstalkPrice.test.js b/protocol/test/beanstalkPrice.test.js index 732a44c829..cbae75286c 100644 --- a/protocol/test/beanstalkPrice.test.js +++ b/protocol/test/beanstalkPrice.test.js @@ -7,7 +7,7 @@ const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); const { deployWell, setReserves, whitelistWell } = require('../utils/well.js'); const { setEthUsdPrice, setEthUsdcPrice, setEthUsdtPrice } = require('../scripts/usdOracle.js'); const { getBeanstalk } = require('../utils/contracts.js'); -const { impersonateBeanEthWell } = require('../scripts/impersonate.js') +const { impersonateBeanEthWell } = require('../utils/well.js') const fs = require('fs'); let user, user2, owner; diff --git a/protocol/utils/well.js b/protocol/utils/well.js index da72021ea1..c13745e162 100644 --- a/protocol/utils/well.js +++ b/protocol/utils/well.js @@ -2,9 +2,9 @@ const fs = require('fs'); const { BEAN, WETH, BEANSTALK_PUMP, BEAN_ETH_WELL } = require('../test/utils/constants'); const { to6, to18 } = require('../test/utils/helpers'); const { getBeanstalk } = require('./contracts'); -const { mintEth } = require('./mint'); const { impersonateBeanstalkOwner } = require('./signer'); const { increaseToNonce } = require('../scripts/contracts'); +const { impersonateContract } = require('../scripts/impersonate'); const BASE_STRING = './node_modules/@beanstalk/wells/out'; @@ -38,7 +38,7 @@ async function deployWellContract(name, arguments = [], account = undefined, ver return contract; } -async function deployMockToken(name="MockToken", symbol="MOCK") { +async function deployMockToken(name = "MockToken", symbol = "MOCK") { const MockToken = await ethers.getContractFactory('MockToken'); const mockToken = await MockToken.deploy(name, symbol); await mockToken.deployed(); @@ -63,7 +63,7 @@ function encodeWellImmutableData( ] ) } - + immutableData = ethers.utils.solidityPack( [ 'address', // aquifer address @@ -75,15 +75,15 @@ function encodeWellImmutableData( 'bytes', // well function data (bytes) 'bytes' // packed pumps (bytes) ], [ - aquifer, // aquifer address - tokens.length, // number of tokens - wellFunction.target, // well function address - wellFunction.length, // well function data length - pumps.length, // number of pumps - tokens, // tokens array - wellFunction.data, // well function data (bytes) - packedPumps // packed pumps (bytes) - ] + aquifer, // aquifer address + tokens.length, // number of tokens + wellFunction.target, // well function address + wellFunction.length, // well function data length + pumps.length, // number of pumps + tokens, // tokens array + wellFunction.data, // well function data (bytes) + packedPumps // packed pumps (bytes) + ] ); return immutableData } @@ -107,7 +107,7 @@ async function deployWell(tokens, verbose = false, salt = ethers.constants.HashZ aquifer.address, tokens, { target: wellFunction.address, data: '0x', length: 0 }, - [{target: pump.address, data: '0x', length: 0 }] + [{ target: pump.address, data: '0x', length: 0 }] ) const initData = await encodeInitFunctionCall(); @@ -181,6 +181,27 @@ async function setReserves(account, well, amounts) { } } +async function impersonateBeanEthWell() { + const well = await deployWell([BEAN, WETH]); + const bytecode = await ethers.provider.getCode(well.address) + await network.provider.send("hardhat_setCode", [ + BEAN_ETH_WELL, + bytecode, + ]); +} + +async function impersonateMockWell(pumpBalances = [to18('1'), to18('1')]) { + well = await impersonateContract('MockSetComponentsWell', BEAN_ETH_WELL) + pump = await deployMockPump() + wellFunction = await (await getWellContractFactory('ConstantProduct2')).deploy() + await well.setPumps([[this.pump.address, '0x']]) + await well.setWellFunction([this.wellFunction.address, '0x']) + await well.setTokens([BEAN, WETH]) + pump.setInstantaneousReserves(pumpBalances) + await whitelistWell(this.well.address, '10000', to6('4')) + return [well, pump, wellFunction] +} + async function whitelistWell(wellAddress, stalk, stalkEarnedPerSeason) { const beanstalk = await getBeanstalk() @@ -199,24 +220,24 @@ async function deployMockPump() { pump = await (await ethers.getContractFactory('MockPump')).deploy() await pump.deployed() await network.provider.send("hardhat_setCode", [ - BEANSTALK_PUMP, - await ethers.provider.getCode(pump.address), + BEANSTALK_PUMP, + await ethers.provider.getCode(pump.address), ]); return await ethers.getContractAt('MockPump', BEANSTALK_PUMP) } async function deployMultiFlowPump() { pump = await (await getWellContractFactory('MultiFlowPump')).deploy( - '0x3ffe0000000000000000000000000000', // 0.5 - '0x3ffd555555555555553cbcd83d925070', // 0.333333333333333333 - 12, - '0x3ffecccccccccccccccccccccccccccc' // 0.9 + '0x3ffe0000000000000000000000000000', // 0.5 + '0x3ffd555555555555553cbcd83d925070', // 0.333333333333333333 + 12, + '0x3ffecccccccccccccccccccccccccccc' // 0.9 ) await pump.deployed() await network.provider.send("hardhat_setCode", [ - BEANSTALK_PUMP, - await ethers.provider.getCode(pump.address), + BEANSTALK_PUMP, + await ethers.provider.getCode(pump.address), ]); return await getWellContractAt('MultiFlowPump', BEANSTALK_PUMP) } @@ -231,7 +252,7 @@ async function deployMockWell() { await network.provider.send("hardhat_setCode", [ BEAN_ETH_WELL, await ethers.provider.getCode(well.address), - ]); + ]); well = await ethers.getContractAt('MockSetComponentsWell', BEAN_ETH_WELL) await well.init() @@ -260,4 +281,6 @@ exports.deployMockWell = deployMockWell exports.deployMockPump = deployMockPump exports.deployWellContract = deployWellContract exports.deployWellContractAtNonce = deployWellContractAtNonce -exports.encodeWellImmutableData = encodeWellImmutableData \ No newline at end of file +exports.encodeWellImmutableData = encodeWellImmutableData +exports.impersonateMockWell = impersonateMockWell +exports.impersonateBeanEthWell = impersonateBeanEthWell \ No newline at end of file From f14ab7c65db86c7004acba7ba182711e5300171f Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:39:53 -0400 Subject: [PATCH 11/96] remove extra line --- protocol/contracts/beanstalk/barn/UnripeFacet.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 764b5c598e..74bca8ba5a 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -54,7 +54,6 @@ contract UnripeFacet is ReentrancyGuard { LibTransfer.From fromMode, LibTransfer.To toMode ) external payable nonReentrant returns (uint256 underlyingAmount) { - uint256 unripeSupply = IERC20(unripeToken).totalSupply(); amount = LibTransfer.burnToken(IBean(unripeToken), amount, msg.sender, fromMode); From b727a7d241eae6744dbe27153e8819e44aafb275 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:40:03 -0400 Subject: [PATCH 12/96] update abi --- protocol/abi/Beanstalk.json | 56 ++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/protocol/abi/Beanstalk.json b/protocol/abi/Beanstalk.json index 36db529a39..1e59bd6d06 100644 --- a/protocol/abi/Beanstalk.json +++ b/protocol/abi/Beanstalk.json @@ -128,6 +128,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "unripeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "addMigratedUnderlying", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -800,6 +818,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "wethAmountIn", + "type": "uint256" + } + ], + "name": "getMintFertilizerOut", + "outputs": [ + { + "internalType": "uint256", + "name": "fertilizerAmountOut", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -835,9 +872,14 @@ { "inputs": [ { - "internalType": "uint128", - "name": "amount", - "type": "uint128" + "internalType": "uint256", + "name": "wethAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minFertilizerOut", + "type": "uint256" }, { "internalType": "uint256", @@ -851,7 +893,13 @@ } ], "name": "mintFertilizer", - "outputs": [], + "outputs": [ + { + "internalType": "uint256", + "name": "fertilizerAmountOut", + "type": "uint256" + } + ], "stateMutability": "payable", "type": "function" }, From 87219b9be04182e03726c0bd9410160ad2251b6c Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:40:16 -0400 Subject: [PATCH 13/96] update verbose flag --- protocol/scripts/bips.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/scripts/bips.js b/protocol/scripts/bips.js index c40351a4a1..07db151aaf 100644 --- a/protocol/scripts/bips.js +++ b/protocol/scripts/bips.js @@ -163,7 +163,7 @@ async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefine selectorsToRemove: [ '0x0bfca7e3' ], bip: false, object: !mock, - verbose: true, + verbose: verbose, account: account, verify: false }); From 900b9d508c6f907a164fa261774f5360675bed09 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:40:35 -0400 Subject: [PATCH 14/96] update mint eth amount --- protocol/utils/mint.js | 2 +- protocol/utils/signer.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/utils/mint.js b/protocol/utils/mint.js index 21291deb8b..1dce1ca778 100644 --- a/protocol/utils/mint.js +++ b/protocol/utils/mint.js @@ -15,7 +15,7 @@ async function mintBeans(address, amount) { } async function mintEth(address) { - await hre.network.provider.send("hardhat_setBalance", [address, "0x3635C9ADC5DEA00000"]); + await hre.network.provider.send("hardhat_setBalance", [address, "0x21E19E0C9BAB2400000"]); } exports.mintEth = mintEth; diff --git a/protocol/utils/signer.js b/protocol/utils/signer.js index d6434dd96f..46d435f0d8 100644 --- a/protocol/utils/signer.js +++ b/protocol/utils/signer.js @@ -7,7 +7,7 @@ async function impersonateSigner(signerAddress, withEth = false) { }); if (withEth) { - await hre.network.provider.send("hardhat_setBalance", [signerAddress, "0x3635C9ADC5DEA00000"]); + await hre.network.provider.send("hardhat_setBalance", [signerAddress, "0x21E19E0C9BAB2400000"]); } return await ethers.getSigner(signerAddress) From 9530ba20507a3dae44ae1de0f530f133267d0f56 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:40:52 -0400 Subject: [PATCH 15/96] add migration test --- .../test/Bean3CrvToBeanEthMigration.test.js | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 protocol/test/Bean3CrvToBeanEthMigration.test.js diff --git a/protocol/test/Bean3CrvToBeanEthMigration.test.js b/protocol/test/Bean3CrvToBeanEthMigration.test.js new file mode 100644 index 0000000000..cb1393b638 --- /dev/null +++ b/protocol/test/Bean3CrvToBeanEthMigration.test.js @@ -0,0 +1,112 @@ +const { expect } = require('chai'); +const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot.js"); +const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK, BEAN_ETH_WELL, BCM, STABLE_FACTORY } = require('./utils/constants.js'); +const { setEthUsdcPrice, setEthUsdPrice } = require('../utils/oracle.js'); +const { to6, to18 } = require('./utils/helpers.js'); +const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); +const { getBeanstalk } = require('../utils/contracts.js'); +const { impersonateBeanstalkOwner } = require('../utils/signer.js'); +const { ethers } = require('hardhat'); +const { mintEth } = require('../utils/mint.js'); +let user,user2,owner; + +let underlyingBefore +let beanEthUnderlying +let snapshotId + + +describe('Bean:3Crv to Bean:Eth Migration', function () { + before(async function () { + + [user, user2] = await ethers.getSigners() + + try { + await network.provider.request({ + method: "hardhat_reset", + params: [ + { + forking: { + jsonRpcUrl: process.env.FORKING_RPC, + blockNumber: 18072000 //a random semi-recent block close to Grown Stalk Per Bdv pre-deployment + }, + }, + ], + }); + } catch(error) { + console.log('forking error in Silo V3: Grown Stalk Per Bdv:'); + console.log(error); + return + } + + owner = await impersonateBeanstalkOwner() + this.beanstalk = await getBeanstalk() + this.weth = await ethers.getContractAt('IWETH', WETH) + this.bean = await ethers.getContractAt('IBean', BEAN) + this.beanEth = await ethers.getContractAt('IWell', BEAN_ETH_WELL) + this.beanEthToken = await ethers.getContractAt('IERC20', BEAN_ETH_WELL) + this.unripeLp = await ethers.getContractAt('IERC20', UNRIPE_LP) + this.beanMetapool = await ethers.getContractAt('MockMeta3Curve', BEAN_3_CURVE) + underlyingBefore = await this.beanstalk.getTotalUnderlying(UNRIPE_LP); + + await bipMigrateUnripeBean3CrvToBeanEth(true, undefined, false) + }); + + beforeEach(async function () { + snapshotId = await takeSnapshot() + }); + + afterEach(async function () { + await revertToSnapshot(snapshotId) + }); + + describe('Initializes migration', async function () { + it('Changings underlying token', async function () { + expect(await this.beanstalk.getUnderlyingToken(UNRIPE_LP)).to.be.equal(BEAN_ETH_WELL) + }) + + it('Removes underlying balance', async function () { + expect(await this.beanstalk.getTotalUnderlying(UNRIPE_LP)).to.be.equal(0) + }) + + it('Sends underlying balance to BCM', async function () { + expect(await this.beanstalk.getExternalBalance(BCM, BEAN_3_CURVE)).to.be.equal(underlyingBefore) + }) + }) + + describe('Completes Migration', async function () { + beforeEach(async function () { + const balance = await this.beanMetapool.balanceOf(owner.address) + await this.beanMetapool.connect(owner).approve(BEANSTALK, balance) + await this.beanstalk.connect(owner).removeLiquidity( + BEAN_3_CURVE, + STABLE_FACTORY, + balance, + ['0', '0'], + '0', + '0' + ) + const balances = await this.beanEth.getReserves(); + const beans = await this.bean.balanceOf(owner.address) + const weth = beans.mul(balances[1]).div(balances[0]) + await this.weth.connect(owner).deposit({value: weth}) + + await this.weth.connect(owner).approve(BEAN_ETH_WELL, weth) + await this.bean.connect(owner).approve(BEAN_ETH_WELL, beans) + + await this.beanEth.connect(owner).addLiquidity( + [beans, weth], + 0, + owner.address, + ethers.constants.MaxUint256 + ); + beanEthUnderlying = await this.beanEthToken.balanceOf(owner.address) + await this.beanEthToken.connect(owner).approve(BEANSTALK, beanEthUnderlying) + await this.beanstalk.connect(owner).addMigratedUnderlying(UNRIPE_LP, beanEthUnderlying); + }) + + it("successfully adds underlying", async function () { + expect(await this.beanstalk.getTotalUnderlying(UNRIPE_LP)).to.be.equal(beanEthUnderlying) + expect(await this.beanstalk.getUnderlying(UNRIPE_LP, await this.unripeLp.totalSupply())).to.be.equal(beanEthUnderlying) + }) + }) +}) \ No newline at end of file From 6c57d1e2cc4080413fbe334ee1d8d5d887f34eba Mon Sep 17 00:00:00 2001 From: brendan Date: Sun, 10 Sep 2023 11:54:17 -0400 Subject: [PATCH 16/96] revert on 0 before migration completed --- .../contracts/beanstalk/barn/UnripeFacet.sol | 2 + .../test/Bean3CrvToBeanEthMigration.test.js | 42 ++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 74bca8ba5a..568d948895 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -60,6 +60,8 @@ contract UnripeFacet is ReentrancyGuard { underlyingAmount = _getPenalizedUnderlying(unripeToken, amount, unripeSupply); + require(underlyingAmount > 0, "Chop: no underlying"); + LibUnripe.decrementUnderlying(unripeToken, underlyingAmount); address underlyingToken = s.u[unripeToken].underlyingToken; diff --git a/protocol/test/Bean3CrvToBeanEthMigration.test.js b/protocol/test/Bean3CrvToBeanEthMigration.test.js index cb1393b638..7cf06735d1 100644 --- a/protocol/test/Bean3CrvToBeanEthMigration.test.js +++ b/protocol/test/Bean3CrvToBeanEthMigration.test.js @@ -1,14 +1,18 @@ const { expect } = require('chai'); const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot.js"); -const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK, BEAN_ETH_WELL, BCM, STABLE_FACTORY } = require('./utils/constants.js'); +const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK, BEAN_ETH_WELL, BCM, STABLE_FACTORY, PUBLIUS } = require('./utils/constants.js'); const { setEthUsdcPrice, setEthUsdPrice } = require('../utils/oracle.js'); const { to6, to18 } = require('./utils/helpers.js'); const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); const { getBeanstalk } = require('../utils/contracts.js'); -const { impersonateBeanstalkOwner } = require('../utils/signer.js'); +const { impersonateBeanstalkOwner, impersonateSigner } = require('../utils/signer.js'); const { ethers } = require('hardhat'); const { mintEth } = require('../utils/mint.js'); +const { ConvertEncoder } = require('./utils/encoder.js'); +const { setReserves } = require('../utils/well.js'); +const { toBN } = require('../utils/helpers.js'); let user,user2,owner; +let publius; let underlyingBefore let beanEthUnderlying @@ -38,8 +42,11 @@ describe('Bean:3Crv to Bean:Eth Migration', function () { return } + publius = await impersonateSigner(PUBLIUS, true) + owner = await impersonateBeanstalkOwner() this.beanstalk = await getBeanstalk() + this.well = await ethers.getContractAt('IWell', BEAN_ETH_WELL); this.weth = await ethers.getContractAt('IWETH', WETH) this.bean = await ethers.getContractAt('IBean', BEAN) this.beanEth = await ethers.getContractAt('IWell', BEAN_ETH_WELL) @@ -71,6 +78,37 @@ describe('Bean:3Crv to Bean:Eth Migration', function () { it('Sends underlying balance to BCM', async function () { expect(await this.beanstalk.getExternalBalance(BCM, BEAN_3_CURVE)).to.be.equal(underlyingBefore) }) + + describe('Interactions with Unripe fail', async function () { + it('chop fails', async function () { + await this.beanstalk.connect(publius).withdrawDeposit(UNRIPE_LP, '-56836', to6('1'), 1); + await expect(this.beanstalk.connect(publius).chop(UNRIPE_LP, to6('1'), 1, 0)).to.be.revertedWith("Chop: no underlying") + }) + + it('deposit fails', async function () { + await this.beanstalk.connect(publius).withdrawDeposit(UNRIPE_LP, '-56836', to6('1'), 1); + await expect(this.beanstalk.connect(publius).deposit(UNRIPE_LP, to6('1'), 1)).to.be.revertedWith('Silo: No Beans under Token.') + }) + + it('enrootDeposit fails', async function () { + await expect(this.beanstalk.connect(publius).enrootDeposit(UNRIPE_LP, '-56836', to6('1'))).to.be.revertedWith('SafeMath: subtraction overflow'); + }) + + it('enrootDeposits fails', async function () { + await expect(this.beanstalk.connect(publius).enrootDeposits(UNRIPE_LP, ['-56836'], [to6('1')])).to.be.revertedWith('SafeMath: subtraction overflow'); + }) + + it('convert Unripe Bean to LP fails', async function () { + console.log(await this.beanstalk.poolDeltaB(BEAN_ETH_WELL)) + await expect(this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['-16272'], [to6('200')])).to.be.revertedWith('SafeMath: subtraction overflow'); + }) + + it('convert Unripe LP to Bean fails', async function () { + const liquidityRemover = await impersonateSigner('0x7eaE23DD0f0d8289d38653BCE11b92F7807eFB64', true); + await this.well.connect(liquidityRemover).removeLiquidityOneToken(to18('29'), WETH, '0', liquidityRemover.address, ethers.constants.MaxUint256) + await expect(this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeLPToBeans(to6('200'), '0'), ['-56836'], [to6('200')])).to.be.revertedWith('SafeMath: division by zero'); + }) + }) }) describe('Completes Migration', async function () { From 46fb327fb3d752fa4348d774a8089d8e32592680 Mon Sep 17 00:00:00 2001 From: brendan Date: Sun, 10 Sep 2023 11:54:34 -0400 Subject: [PATCH 17/96] update tests --- protocol/test/ConvertUnripe.test.js | 708 ++++++++++++++++------------ 1 file changed, 396 insertions(+), 312 deletions(-) diff --git a/protocol/test/ConvertUnripe.test.js b/protocol/test/ConvertUnripe.test.js index 4f6ad62a60..d77e2e8c74 100644 --- a/protocol/test/ConvertUnripe.test.js +++ b/protocol/test/ConvertUnripe.test.js @@ -1,10 +1,13 @@ const { expect } = require('chai'); const { deploy } = require('../scripts/deploy.js') const { EXTERNAL, INTERNAL, INTERNAL_EXTERNAL, INTERNAL_TOLERANT } = require('./utils/balances.js') -const { BEAN, THREE_CURVE, THREE_POOL, BEAN_3_CURVE, UNRIPE_BEAN, UNRIPE_LP } = require('./utils/constants') +const { BEAN, THREE_CURVE, THREE_POOL, BEAN_3_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK, BEAN_ETH_WELL } = require('./utils/constants') const { ConvertEncoder } = require('./utils/encoder.js') const { to6, to18, toBean, toStalk } = require('./utils/helpers.js') const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); +const { setEthUsdcPrice, setEthUsdPrice, setEthUsdtPrice, setOracleFailure, printPrices } = require('../utils/oracle.js'); +const { deployBasin } = require('../scripts/basin.js'); +const { toBN } = require('../utils/helpers.js'); const ZERO_BYTES = ethers.utils.formatBytes32String('0x0') let user, user2, owner; let userAddress, ownerAddress, user2Address; @@ -23,41 +26,52 @@ describe('Unripe Convert', function () { this.convert = await ethers.getContractAt('ConvertFacet', this.diamond.address); this.convertGet = await ethers.getContractAt('ConvertGettersFacet', this.diamond.address); this.bean = await ethers.getContractAt('MockToken', BEAN); - this.threePool = await ethers.getContractAt('Mock3Curve', THREE_POOL); - this.threeCurve = await ethers.getContractAt('MockToken', THREE_CURVE); - this.beanMetapool = await ethers.getContractAt('IMockCurvePool', BEAN_3_CURVE); + this.weth = await ethers.getContractAt('MockToken', WETH); - await this.threeCurve.mint(userAddress, to18('100000')); - await this.threePool.set_virtual_price(to18('1')); - await this.threeCurve.connect(user).approve(this.beanMetapool.address, to18('100000000000')); + this.well = await deployBasin(true, undefined, false, true) + this.wellToken = await ethers.getContractAt("IERC20", this.well.address) + await this.wellToken.connect(owner).approve(BEANSTALK, ethers.constants.MaxUint256) + await this.bean.connect(owner).approve(BEANSTALK, ethers.constants.MaxUint256) - await this.beanMetapool.connect(user).approve(this.threeCurve.address, to18('100000000000')); - await this.beanMetapool.connect(user).approve(this.silo.address, to18('100000000000')); + await setEthUsdPrice('999.998018') + await setEthUsdcPrice('1000') await this.season.siloSunrise(0); - await this.bean.mint(userAddress, toBean('1000000000')); - await this.bean.mint(user2Address, toBean('1000000000')); - await this.bean.connect(user).approve(this.beanMetapool.address, to18('100000000000')); - await this.bean.connect(user2).approve(this.beanMetapool.address, to18('100000000000')); - await this.bean.connect(user).approve(this.silo.address, '100000000000'); - await this.bean.connect(user2).approve(this.silo.address, '100000000000'); - await this.beanMetapool.connect(user).add_liquidity([toBean('1000'), to18('1000')], to18('2000')); - await this.beanMetapool.connect(user).transfer(ownerAddress, to18('1000')) + await this.bean.mint(userAddress, toBean('10000000000')); + await this.bean.mint(user2Address, toBean('10000000000')); + await this.weth.mint(userAddress, to18('1000000000')); + await this.weth.mint(user2Address, to18('1000000000')); + + await this.bean.connect(user).approve(this.well.address, ethers.constants.MaxUint256); + await this.bean.connect(user2).approve(this.well.address, ethers.constants.MaxUint256); + await this.bean.connect(owner).approve(this.well.address, ethers.constants.MaxUint256); + await this.weth.connect(user).approve(this.well.address, ethers.constants.MaxUint256); + await this.weth.connect(user2).approve(this.well.address, ethers.constants.MaxUint256); + await this.weth.connect(owner).approve(this.well.address, ethers.constants.MaxUint256); + await this.bean.connect(user).approve(this.silo.address, ethers.constants.MaxUint256); + await this.bean.connect(user2).approve(this.silo.address, ethers.constants.MaxUint256); + await this.wellToken.connect(user).approve(this.silo.address, ethers.constants.MaxUint256); + await this.wellToken.connect(user2).approve(this.silo.address, ethers.constants.MaxUint256); + + await this.well.connect(user).addLiquidity( + [toBean('10000'), to18('10')], + 0, + owner.address, + ethers.constants.MaxUint256 + ); this.unripe = await ethers.getContractAt('MockUnripeFacet', this.diamond.address) this.unripeBean = await ethers.getContractAt('MockToken', UNRIPE_BEAN) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) this.fertilizer = await ethers.getContractAt('MockFertilizerFacet', this.diamond.address) await this.unripeBean.mint(userAddress, to6('10000')) - await this.unripeLP.mint(userAddress, to6('9422.960000')) + await this.unripeLP.mint(userAddress, to6('31.622776')) await this.unripeBean.connect(user).approve(this.diamond.address, to18('100000000')) await this.unripeLP.connect(user).approve(this.diamond.address, to18('100000000')) await this.fertilizer.setFertilizerE(true, to6('10000')) await this.unripe.addUnripeToken(UNRIPE_BEAN, BEAN, ZERO_BYTES) - await this.unripe.addUnripeToken(UNRIPE_LP, BEAN_3_CURVE, ZERO_BYTES) + await this.unripe.addUnripeToken(UNRIPE_LP, BEAN_ETH_WELL, ZERO_BYTES) await this.bean.mint(ownerAddress, to6('5000')) - await this.bean.approve(this.diamond.address, to6('5000')) - await this.beanMetapool.approve(this.diamond.address, to18('10000')) await this.fertilizer.setPenaltyParams(to6('500'), '0') await this.unripe.connect(owner).addUnderlying( UNRIPE_BEAN, @@ -65,7 +79,7 @@ describe('Unripe Convert', function () { ) await this.unripe.connect(owner).addUnderlying( UNRIPE_LP, - to18('942.2960000') + to18('31.622776') // 31.622776601683793319 ) }); @@ -79,7 +93,12 @@ describe('Unripe Convert', function () { describe('calclates beans to peg', async function () { it('p > 1', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); + await this.well.connect(user).addLiquidity( + [toBean('0'), to18('0.2')], + '0', + user.address, + ethers.constants.MaxUint256 + ); expect(await this.convertGet.getMaxAmountIn(UNRIPE_BEAN, UNRIPE_LP)).to.be.equal(to6('2000')); }); @@ -88,15 +107,25 @@ describe('Unripe Convert', function () { }); it('p < 1', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); + await this.well.connect(user).addLiquidity( + [toBean('2000'), to18('0')], + '0', + user.address, + ethers.constants.MaxUint256 + ); expect(await this.convertGet.getMaxAmountIn(UNRIPE_BEAN, UNRIPE_LP)).to.be.equal('0'); }); }); describe('calclates lp to peg', async function () { it('p > 1', async function () { - await this.beanMetapool.connect(user2).add_liquidity([toBean('200'), to18('0')], to18('150')); - expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.within(to6('1990'), to6('2000')); + await this.well.connect(user).addLiquidity( + [toBean('0'), to18('0.2')], + '0', + user.address, + ethers.constants.MaxUint256 + ); + expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal('0'); }); it('p = 1', async function () { @@ -104,8 +133,13 @@ describe('Unripe Convert', function () { }); it('p < 1', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal('0'); + await this.well.connect(user).addLiquidity( + [toBean('2000'), to18('0')], + '0', + user.address, + ethers.constants.MaxUint256 + ); + expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal(to6('30.182395')); }); }) @@ -118,14 +152,15 @@ describe('Unripe Convert', function () { }); it('not enough LP', async function () { await this.silo.connect(user).deposit(this.unripeBean.address, to6('200'), EXTERNAL); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('20')], to18('15')); - await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), to6('200.1')), ['0'], [to6('200')])) - .to.be.revertedWith('Curve: Not enough LP'); + await this.well.connect(user).addLiquidity([toBean('0'), to18('0.02')], '0', user.address, ethers.constants.MaxUint256); + const amountOut = await this.well.getAddLiquidityOut([to6('200'), '0']) + await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), amountOut.add(toBN('1'))), ['0'], [to6('200')])) + .to.be.revertedWith('') }); it('p >= 1', async function () { await this.silo.connect(user).deposit(this.unripeBean.address, to6('200'), EXTERNAL); - await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), to6('190')), ['0'], ['1000'])) + await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['0'], ['1000'])) .to.be.revertedWith('Convert: P must be >= 1.'); }); }); @@ -136,307 +171,356 @@ describe('Unripe Convert', function () { this.season.deployStemsUpgrade(); }); beforeEach(async function () { - await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('1000'), to6('1000')), ['0'], [to6('2000')]) + await this.silo.connect(user).deposit( + this.unripeBean.address, to6('2000'), EXTERNAL + ); + await this.well.connect(user).addLiquidity( + [toBean('0'), to18('0.2')], + '0', + user.address, + ethers.constants.MaxUint256 + ); + this.result = await this.convert.connect(user).convert( + ConvertEncoder.convertUnripeBeansToLP(to6('1000'), '0'), ['0'], [to6('2000')] + ) }); it('properly updates total values', async function () { expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1000')); expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('1006344767'); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); - //expect(await this.silo.totalSeeds()).to.eq(toBean('600')); - expect(await this.silo.totalStalk()).to.eq(toStalk('200')); + expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('474652298'); + const bdv = await this.silo.bdv(this.unripeLP.address, '474652298') + expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(bdv); + expect(await this.silo.totalStalk()).to.eq(toStalk('100').add(bdv.mul(to6('0.01')))); }); - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(toBean('600')); - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200')); + it('properly updates user values -test', async function () { + const bdv = await this.silo.bdv(this.unripeLP.address, '474652298') + expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('100').add(bdv.mul(to6('0.01')))); }); it('properly updates user deposits', async function () { expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1000')); const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); - expect(deposit[0]).to.eq('1006344767'); - expect(deposit[1]).to.eq(toBean('100')); + expect(deposit[0]).to.eq('474652298'); + expect(deposit[1]).to.eq(await this.silo.bdv(this.unripeLP.address, '474652298')); }); it('emits events', async function () { await expect(this.result).to.emit(this.silo, 'RemoveDeposits') .withArgs(userAddress, this.unripeBean.address, [0], [to6('1000')], to6('1000'), [to6('100')]); await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 0, '1006344767', toBean('100')); - }); - }); - - describe('multiple crates', async function () { - beforeEach(async function () { - await this.season.teleportSunrise(10); - this.season.deployStemsUpgrade(); - await this.silo.connect(user).deposit(this.unripeBean.address, to6('1000'), EXTERNAL); - await this.season.siloSunrise(0); - await this.season.siloSunrise(0); - await this.season.siloSunrise(0); - await this.season.siloSunrise(0); //season 14 - - await this.silo.connect(user).deposit(this.unripeBean.address, to6('1000'), EXTERNAL); - - - const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('2500'), to6('1900')), [0, stemUnripeBean], [to6('1000'), to6('1000')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to18('0')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to18('0')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('2008324306'); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('200')); - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200.08')); - }); - - it('properly updates user values', async function () { - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200.08')); - }); - - it('properly updates user deposits', async function () { - const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); - - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(toBean('0')); - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, stemUnripeBean))[0]).to.eq(toBean('0')); - const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 4); - expect(deposit[0]).to.eq('2008324306'); - expect(deposit[1]).to.eq(toBean('200')); - }); - - it('emits events', async function () { - const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); - await expect(this.result).to.emit(this.silo, 'RemoveDeposits') - .withArgs(userAddress, this.unripeBean.address, [0, stemUnripeBean], [to6('1000'), to6('1000')], to6('2000'), [to6('100'), to6('100')]); - await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 4, '2008324306', toBean('200')); + .withArgs(userAddress, this.unripeLP.address, 0, '474652298', await this.silo.bdv(this.unripeLP.address, '474652298')); }); }); - //TODOSEEDS maybe write some tests that are not right on the zero index of grown stalk per bdv? - describe("bean more vested", async function () { - beforeEach(async function () { - await this.season.teleportSunrise(10); - this.season.deployStemsUpgrade(); - await this.unripe.connect(owner).addUnderlying( - UNRIPE_BEAN, - to6('1000') - ) - await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('500'), to6('500')), ['0'], [to6('500')]) - }) - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1500')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('300')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('503172383'); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); - //expect(await this.silo.totalSeeds()).to.eq(toBean('1000')); - expect(await this.silo.totalStalk()).to.eq(toStalk('400')); - }); - - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(toBean('1000')); - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('400')); - }); - - it('properly updates user deposits', async function () { - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1500')); - const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); - expect(deposit[0]).to.eq('503172383'); - expect(deposit[1]).to.eq(toBean('100')); - }); - - it('emits events', async function () { - await expect(this.result).to.emit(this.silo, 'RemoveDeposits') - .withArgs(userAddress, this.unripeBean.address, [0], [to6('500')], to6('500'), [to6('100')]); - await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 0, '503172383', toBean('100')); - }); - }) - - describe("lp more vested", async function () { - beforeEach(async function () { - await this.season.teleportSunrise(10); - this.season.deployStemsUpgrade(); - await this.unripe.connect(user).addUnderlyingWithRecap( - UNRIPE_LP, - to18('942.2960000') - ) - await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('500'), to6('500')), ['0'], [to6('500')]) - }) - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1500')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('150')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('503761210'); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq('97342214'); - expect(await this.silo.totalStalk()).to.eq('2473422140000'); - }); - - it('properly updates user values', async function () { - expect(await this.silo.balanceOfStalk(userAddress)).to.eq('2473422140000'); - }); - - it('properly updates user deposits', async function () { - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1500')); - const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); - expect(deposit[0]).to.eq('503761210'); - expect(deposit[1]).to.eq('97342214'); - }); - - it('emits events', async function () { - await expect(this.result).to.emit(this.silo, 'RemoveDeposits') - .withArgs(userAddress, this.unripeBean.address, [0], [to6('500')], to6('500'), [to6('50')]); - await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 0, '503761210', '97342214'); - }); - }) +// describe('multiple crates', async function () { +// beforeEach(async function () { +// await this.season.teleportSunrise(10); +// this.season.deployStemsUpgrade(); +// await this.silo.connect(user).deposit(this.unripeBean.address, to6('1000'), EXTERNAL); +// await this.season.siloSunrise(0); +// await this.season.siloSunrise(0); +// await this.season.siloSunrise(0); +// await this.season.siloSunrise(0); //season 14 + +// await this.silo.connect(user).deposit(this.unripeBean.address, to6('1000'), EXTERNAL); + + +// const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); +// await this.well.connect(user).addLiquidity( +// [toBean('0'), to18('0.2')], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('2500'), '0'), [0, stemUnripeBean], [to6('1000'), to6('1000')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to18('0')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to18('0')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('2008324306'); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('200')); +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200.08')); +// }); + +// it('properly updates user values', async function () { +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200.08')); +// }); + +// it('properly updates user deposits', async function () { +// const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); + +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(toBean('0')); +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, stemUnripeBean))[0]).to.eq(toBean('0')); +// const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 4); +// expect(deposit[0]).to.eq('2008324306'); +// expect(deposit[1]).to.eq(toBean('200')); +// }); + +// it('emits events', async function () { +// const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); +// await expect(this.result).to.emit(this.silo, 'RemoveDeposits') +// .withArgs(userAddress, this.unripeBean.address, [0, stemUnripeBean], [to6('1000'), to6('1000')], to6('2000'), [to6('100'), to6('100')]); +// await expect(this.result).to.emit(this.silo, 'AddDeposit') +// .withArgs(userAddress, this.unripeLP.address, 4, '2008324306', toBean('200')); +// }); +// }); +// //TODOSEEDS maybe write some tests that are not right on the zero index of grown stalk per bdv? +// describe("bean more vested", async function () { +// beforeEach(async function () { +// await this.season.teleportSunrise(10); +// this.season.deployStemsUpgrade(); +// await this.unripe.connect(owner).addUnderlying( +// UNRIPE_BEAN, +// to6('1000') +// ) +// await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); +// await this.well.connect(user).addLiquidity( +// [toBean('0'), to18('0.2')], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('500'), '0'), ['0'], [to6('500')]) +// }) + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1500')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('300')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('503172383'); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); +// //expect(await this.silo.totalSeeds()).to.eq(toBean('1000')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('400')); +// }); + +// it('properly updates user values', async function () { +// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(toBean('1000')); +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('400')); +// }); + +// it('properly updates user deposits', async function () { +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1500')); +// const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); +// expect(deposit[0]).to.eq('503172383'); +// expect(deposit[1]).to.eq(toBean('100')); +// }); + +// it('emits events', async function () { +// await expect(this.result).to.emit(this.silo, 'RemoveDeposits') +// .withArgs(userAddress, this.unripeBean.address, [0], [to6('500')], to6('500'), [to6('100')]); +// await expect(this.result).to.emit(this.silo, 'AddDeposit') +// .withArgs(userAddress, this.unripeLP.address, 0, '503172383', toBean('100')); +// }); +// }) + +// describe("lp more vested", async function () { +// beforeEach(async function () { +// await this.season.teleportSunrise(10); +// this.season.deployStemsUpgrade(); +// await this.unripe.connect(user).addUnderlyingWithRecap( +// UNRIPE_LP, +// to18('942.2960000') +// ) +// await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); +// await this.well.connect(user).addLiquidity( +// [toBean('0'), to18('0.2')], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('500'), '0'), ['0'], [to6('500')]) +// }) + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1500')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('150')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('503761210'); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq('97342214'); +// expect(await this.silo.totalStalk()).to.eq('2473422140000'); +// }); + +// it('properly updates user values', async function () { +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq('2473422140000'); +// }); + +// it('properly updates user deposits', async function () { +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1500')); +// const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); +// expect(deposit[0]).to.eq('503761210'); +// expect(deposit[1]).to.eq('97342214'); +// }); + +// it('emits events', async function () { +// await expect(this.result).to.emit(this.silo, 'RemoveDeposits') +// .withArgs(userAddress, this.unripeBean.address, [0], [to6('500')], to6('500'), [to6('50')]); +// await expect(this.result).to.emit(this.silo, 'AddDeposit') +// .withArgs(userAddress, this.unripeLP.address, 0, '503761210', '97342214'); +// }); +// }) }); - describe('convert lp to beans', async function () { - beforeEach(async function () { - await this.season.teleportSunrise(10); - this.season.deployStemsUpgrade(); - }); - - describe('revert', async function () { - it('not enough Beans', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) - .to.be.revertedWith('Curve: Insufficient Output'); - }); - - it('p >= 1', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('1')], to18('0.5')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) - .to.be.revertedWith('Convert: P must be < 1.'); - }); - }); - - describe('below max', function () { - beforeEach(async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990')), ['0'], [to6('1000')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); - //expect(await this.silo.totalSeeds()).to.eq(to6('201.236334')); - expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); - }); - - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('201.236334')); - expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); - }); - }); - - //these tests use the new 2 seeds per bdv instead of previous 4 (note in the beforeEach above that deployStemsUpgrade is called) - describe('multiple crates', function () { - beforeEach(async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('500'), EXTERNAL); - - await this.season.siloSunrise(0); - await this.season.siloSunrise(0); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('500'), EXTERNAL); - - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990'), this.unripeLP.address), ['0', '4'], [to6('500'), to6('500')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); - expect(await this.silo.totalStalk()).to.eq(toStalk('100.6282288167')); - //same as normal curve convert tests, old value was 100.6382906334 but now with rounding it's a bit different - }); - - it('properly updates user values', async function () { - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('100.6282288167')); - }); - - it('properly updates user deposits', async function () { - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 3))[0]).to.eq(to6('1006.18167')); - const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 2); - expect(deposit[0]).to.eq(to6('0')); - expect(deposit[1]).to.eq(toBean('0')); - }); - - it('emits events', async function () { - await expect(this.result).to.emit(this.silo, 'RemoveDeposits') - .withArgs(userAddress, this.unripeLP.address, [0, 4], [to6('500'), to6('500')], to6('1000'), [to6('50'), to6('50')]); - await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeBean.address, 3, to6('1006.18167'), to6('100.618167')); - }); - }); - - describe('bean over vested', function () { - beforeEach(async function () { - await this.unripe.connect(owner).addUnderlying( - UNRIPE_BEAN, - to6('1000') - ) - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('1000')), ['0'], [to6('1000')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('192.037852')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); - //expect(await this.silo.totalSeeds()).to.eq(to6('384.075704')); - expect(await this.silo.totalStalk()).to.eq(toStalk('192.037852')); - }); - - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('384.075704')); - expect(await this.silo.totalStalk()).to.eq(toStalk('192.037852')); - }); - }); - - describe('bean under vested', function () { - beforeEach(async function () { - await this.unripe.connect(user).addUnderlyingWithRecap( - UNRIPE_LP, - to18('942.2960000') - ) - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('500'), to6('500')), ['0'], [to6('1000')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('503.090835')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('500')); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); - //expect(await this.silo.totalSeeds()).to.eq(to6('600')); - expect(await this.silo.totalStalk()).to.eq(toStalk('200')); - }); - - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('600')); - expect(await this.silo.totalStalk()).to.eq(toStalk('200')); - }); - }); - }); +// describe('convert lp to beans', async function () { +// beforeEach(async function () { +// await this.season.teleportSunrise(10); +// this.season.deployStemsUpgrade(); +// }); + +// describe('revert', async function () { +// it('not enough Beans', async function () { +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) +// .to.be.revertedWith('Curve: Insufficient Output'); +// }); + +// it('p >= 1', async function () { +// await this.well.connect(user).addLiquidity([toBean('0'), to18('1')], to18('0.5')); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) +// .to.be.revertedWith('Convert: P must be < 1.'); +// }); +// }); + +// describe('below max', function () { +// beforeEach(async function () { +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990')), ['0'], [to6('1000')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); +// //expect(await this.silo.totalSeeds()).to.eq(to6('201.236334')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); +// }); + +// it('properly updates user values', async function () { +// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('201.236334')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); +// }); +// }); + +// //these tests use the new 2 seeds per bdv instead of previous 4 (note in the beforeEach above that deployStemsUpgrade is called) +// describe('multiple crates', function () { +// beforeEach(async function () { +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('500'), EXTERNAL); + +// await this.season.siloSunrise(0); +// await this.season.siloSunrise(0); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('500'), EXTERNAL); + +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990'), this.unripeLP.address), ['0', '4'], [to6('500'), to6('500')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('100.6282288167')); +// //same as normal curve convert tests, old value was 100.6382906334 but now with rounding it's a bit different +// }); + +// it('properly updates user values', async function () { +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('100.6282288167')); +// }); + +// it('properly updates user deposits', async function () { +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 3))[0]).to.eq(to6('1006.18167')); +// const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 2); +// expect(deposit[0]).to.eq(to6('0')); +// expect(deposit[1]).to.eq(toBean('0')); +// }); + +// it('emits events', async function () { +// await expect(this.result).to.emit(this.silo, 'RemoveDeposits') +// .withArgs(userAddress, this.unripeLP.address, [0, 4], [to6('500'), to6('500')], to6('1000'), [to6('50'), to6('50')]); +// await expect(this.result).to.emit(this.silo, 'AddDeposit') +// .withArgs(userAddress, this.unripeBean.address, 3, to6('1006.18167'), to6('100.618167')); +// }); +// }); + +// describe('bean over vested', function () { +// beforeEach(async function () { +// await this.unripe.connect(owner).addUnderlying( +// UNRIPE_BEAN, +// to6('1000') +// ) +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('1000')), ['0'], [to6('1000')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('192.037852')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); +// //expect(await this.silo.totalSeeds()).to.eq(to6('384.075704')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('192.037852')); +// }); + +// it('properly updates user values', async function () { +// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('384.075704')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('192.037852')); +// }); +// }); + +// describe('bean under vested', function () { +// beforeEach(async function () { +// await this.unripe.connect(user).addUnderlyingWithRecap( +// UNRIPE_LP, +// to18('942.2960000') +// ) +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('500'), to6('500')), ['0'], [to6('1000')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('503.090835')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('500')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); +// //expect(await this.silo.totalSeeds()).to.eq(to6('600')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('200')); +// }); + +// it('properly updates user values', async function () { +// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('600')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('200')); +// }); +// }); +// }); }); From a6918cd847ed4bff8a1421ee43bca4b77beb393f Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 13:18:37 -0400 Subject: [PATCH 18/96] Bean eth migration script --- protocol/scripts/beanEthMigration.js | 90 ++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 protocol/scripts/beanEthMigration.js diff --git a/protocol/scripts/beanEthMigration.js b/protocol/scripts/beanEthMigration.js new file mode 100644 index 0000000000..d8e483aa7e --- /dev/null +++ b/protocol/scripts/beanEthMigration.js @@ -0,0 +1,90 @@ +const { BEAN_ETH_WELL, BEAN_3_CURVE, STABLE_FACTORY, USDT, TRI_CRYPTO_POOL, CURVE_REGISTRY, WETH, BEAN, BEANSTALK, THREE_CURVE, THREE_POOL, CRYPTO_REGISTRY, UNRIPE_LP } = require("../test/utils/constants"); +const { toX } = require("../test/utils/helpers"); +const { getBeanstalk, impersonateBeanstalkOwner } = require("../utils"); + + +async function completeBeanEthMigration() { + const owner = await impersonateBeanstalkOwner() + const beanstalk = await getBeanstalk() + const well = await ethers.getContractAt('IWell', BEAN_ETH_WELL) + const bean3CrvToken = await ethers.getContractAt('IERC20', BEAN_3_CURVE); + const threeCrvToken = await ethers.getContractAt('IERC20', THREE_CURVE); + const bean = await ethers.getContractAt('IERC20', BEAN); + const weth = await ethers.getContractAt('IWETH', WETH); + const beanEthToken = await ethers.getContractAt('IERC20', BEAN_ETH_WELL); + const usdt = await ethers.getContractAt('IERC20', USDT); + let balance = await beanstalk.getExternalBalance(owner.address, BEAN_3_CURVE) + console.log(`Bean 3 Crv Balance: ${balance}`) + await bean3CrvToken.connect(owner).approve(BEANSTALK, balance); + await beanstalk.connect(owner).removeLiquidity( + BEAN_3_CURVE, + STABLE_FACTORY, + balance, + ['0', '0'], + '0', + '0' + ) + + + balance = await beanstalk.getExternalBalance(owner.address, THREE_CURVE) + console.log(`3 Crv Balance: ${balance}`) + await threeCrvToken.connect(owner).approve(BEANSTALK, balance); + await beanstalk.connect(owner).removeLiquidityOneToken( + THREE_POOL, + CURVE_REGISTRY, + USDT, + balance, + '0', + '0', + '0' + ) + balance = await beanstalk.getExternalBalance(owner.address, USDT) + console.log(`USDT: ${balance}`) + await usdt.connect(owner).approve(BEANSTALK, balance); + await beanstalk.connect(owner).exchange( + TRI_CRYPTO_POOL, + CRYPTO_REGISTRY, + USDT, + WETH, + balance, + '0', + '0', + '0' + ) + + let balances = await well.getReserves(); + console.log(`Well Bean Balance Before: ${balances[0]}`); + console.log(`Well WETH Balance Before: ${balances[1]}`); + console.log(`Well Price b4: ${balances[0].mul(toX('1', 12)).div(balances[1])}`) + + const beanBalance = await beanstalk.getExternalBalance(owner.address, BEAN) + const wethBalance = await beanstalk.getExternalBalance(owner.address, WETH) + + const ethToAdd = balances[1].div(balances[0]).mul(beanBalance) + await weth.deposit({value: ethToAdd.sub(wethBalance)}) + + console.log(`Bean Balance: ${beanBalance}`); + console.log(`WETH Balance: ${balances[1]}`); + + await bean.connect(owner).approve(BEAN_ETH_WELL, balances[0]); + await weth.connect(owner).approve(BEAN_ETH_WELL, balances[1]); + await well.connect(owner).addLiquidity( + [beanBalance , ethToAdd], + '0', + owner.address, + ethers.constants.MaxUint256 + ) + + balance = await beanstalk.getExternalBalance(owner.address, BEAN_ETH_WELL) + console.log(`Well LP Balance: ${balance}`) + await beanEthToken.connect(owner).approve(BEANSTALK, balance); + await beanstalk.connect(owner).addMigratedUnderlying(UNRIPE_LP, balance); + console.log(`Unripe LP Underlying Balance: ${await beanstalk.getTotalUnderlying(UNRIPE_LP)}`) + + balances = await well.getReserves(); + console.log(`Well Bean Balance: ${balances[0]}`); + console.log(`Well WETH Balance: ${balances[1]}`); + console.log(`Price after: ${balances[0].mul(toX('1', 12)).div(balances[1])}`) +} + +exports.completeBeanEthMigration = completeBeanEthMigration; \ No newline at end of file From 7dc47b5f51b2e536c08d7ccf9f8d8071fefe3777 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 14:49:28 -0400 Subject: [PATCH 19/96] all tests working --- protocol/scripts/beanEthMigration.js | 72 ++++++------------- .../test/Bean3CrvToBeanEthMigration.test.js | 3 +- protocol/test/Fertilizer.test.js | 2 - protocol/test/Stem.test.js | 50 ++++++++----- protocol/test/Sun.test.js | 29 +++++--- 5 files changed, 72 insertions(+), 84 deletions(-) diff --git a/protocol/scripts/beanEthMigration.js b/protocol/scripts/beanEthMigration.js index d8e483aa7e..b75dd3bdf5 100644 --- a/protocol/scripts/beanEthMigration.js +++ b/protocol/scripts/beanEthMigration.js @@ -1,10 +1,13 @@ const { BEAN_ETH_WELL, BEAN_3_CURVE, STABLE_FACTORY, USDT, TRI_CRYPTO_POOL, CURVE_REGISTRY, WETH, BEAN, BEANSTALK, THREE_CURVE, THREE_POOL, CRYPTO_REGISTRY, UNRIPE_LP } = require("../test/utils/constants"); const { toX } = require("../test/utils/helpers"); const { getBeanstalk, impersonateBeanstalkOwner } = require("../utils"); +const { bipMigrateUnripeBean3CrvToBeanEth } = require("./bips"); - -async function completeBeanEthMigration() { +async function finishBeanEthMigration(verbose = false) { const owner = await impersonateBeanstalkOwner() + + await hre.network.provider.send("hardhat_setBalance", [owner.address, "0x152D02C7E14AF6800000"]); + const beanstalk = await getBeanstalk() const well = await ethers.getContractAt('IWell', BEAN_ETH_WELL) const bean3CrvToken = await ethers.getContractAt('IERC20', BEAN_3_CURVE); @@ -14,7 +17,7 @@ async function completeBeanEthMigration() { const beanEthToken = await ethers.getContractAt('IERC20', BEAN_ETH_WELL); const usdt = await ethers.getContractAt('IERC20', USDT); let balance = await beanstalk.getExternalBalance(owner.address, BEAN_3_CURVE) - console.log(`Bean 3 Crv Balance: ${balance}`) + if (verbose) console.log(`Bean 3 Crv Balance: ${balance}`) await bean3CrvToken.connect(owner).approve(BEANSTALK, balance); await beanstalk.connect(owner).removeLiquidity( BEAN_3_CURVE, @@ -25,66 +28,33 @@ async function completeBeanEthMigration() { '0' ) - - balance = await beanstalk.getExternalBalance(owner.address, THREE_CURVE) - console.log(`3 Crv Balance: ${balance}`) - await threeCrvToken.connect(owner).approve(BEANSTALK, balance); - await beanstalk.connect(owner).removeLiquidityOneToken( - THREE_POOL, - CURVE_REGISTRY, - USDT, - balance, - '0', - '0', - '0' - ) - balance = await beanstalk.getExternalBalance(owner.address, USDT) - console.log(`USDT: ${balance}`) - await usdt.connect(owner).approve(BEANSTALK, balance); - await beanstalk.connect(owner).exchange( - TRI_CRYPTO_POOL, - CRYPTO_REGISTRY, - USDT, - WETH, - balance, - '0', - '0', - '0' - ) - let balances = await well.getReserves(); - console.log(`Well Bean Balance Before: ${balances[0]}`); - console.log(`Well WETH Balance Before: ${balances[1]}`); - console.log(`Well Price b4: ${balances[0].mul(toX('1', 12)).div(balances[1])}`) - const beanBalance = await beanstalk.getExternalBalance(owner.address, BEAN) - const wethBalance = await beanstalk.getExternalBalance(owner.address, WETH) - - const ethToAdd = balances[1].div(balances[0]).mul(beanBalance) - await weth.deposit({value: ethToAdd.sub(wethBalance)}) - - console.log(`Bean Balance: ${beanBalance}`); - console.log(`WETH Balance: ${balances[1]}`); - - await bean.connect(owner).approve(BEAN_ETH_WELL, balances[0]); - await weth.connect(owner).approve(BEAN_ETH_WELL, balances[1]); + const wethBalance = balances[1].div(balances[0]).mul(beanBalance) + await weth.connect(owner).deposit({value: wethBalance}) + await bean.connect(owner).approve(BEAN_ETH_WELL, beanBalance); + await weth.connect(owner).approve(BEAN_ETH_WELL, wethBalance); await well.connect(owner).addLiquidity( - [beanBalance , ethToAdd], + [beanBalance , wethBalance], '0', owner.address, ethers.constants.MaxUint256 ) balance = await beanstalk.getExternalBalance(owner.address, BEAN_ETH_WELL) - console.log(`Well LP Balance: ${balance}`) await beanEthToken.connect(owner).approve(BEANSTALK, balance); await beanstalk.connect(owner).addMigratedUnderlying(UNRIPE_LP, balance); - console.log(`Unripe LP Underlying Balance: ${await beanstalk.getTotalUnderlying(UNRIPE_LP)}`) + if (verbose) console.log(`Unripe LP Underlying Balance: ${await beanstalk.getTotalUnderlying(UNRIPE_LP)}`) balances = await well.getReserves(); - console.log(`Well Bean Balance: ${balances[0]}`); - console.log(`Well WETH Balance: ${balances[1]}`); - console.log(`Price after: ${balances[0].mul(toX('1', 12)).div(balances[1])}`) + if (verbose) console.log(`Well Bean Balance: ${balances[0]}`); + if (verbose) console.log(`Well WETH Balance: ${balances[1]}`); +} + +async function migrateBean3CrvToBeanEth() { + await bipMigrateUnripeBean3CrvToBeanEth() + await finishBeanEthMigration() } -exports.completeBeanEthMigration = completeBeanEthMigration; \ No newline at end of file +exports.finishBeanEthMigration = finishBeanEthMigration; +exports.migrateBean3CrvToBeanEth = migrateBean3CrvToBeanEth; \ No newline at end of file diff --git a/protocol/test/Bean3CrvToBeanEthMigration.test.js b/protocol/test/Bean3CrvToBeanEthMigration.test.js index 7cf06735d1..5970679f8f 100644 --- a/protocol/test/Bean3CrvToBeanEthMigration.test.js +++ b/protocol/test/Bean3CrvToBeanEthMigration.test.js @@ -99,8 +99,7 @@ describe('Bean:3Crv to Bean:Eth Migration', function () { }) it('convert Unripe Bean to LP fails', async function () { - console.log(await this.beanstalk.poolDeltaB(BEAN_ETH_WELL)) - await expect(this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['-16272'], [to6('200')])).to.be.revertedWith('SafeMath: subtraction overflow'); + await expect(this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['-16272'], [to6('200')])).to.be.revertedWith('SafeMath: division by zero'); }) it('convert Unripe LP to Bean fails', async function () { diff --git a/protocol/test/Fertilizer.test.js b/protocol/test/Fertilizer.test.js index adab06a69c..a7a1df7540 100644 --- a/protocol/test/Fertilizer.test.js +++ b/protocol/test/Fertilizer.test.js @@ -43,8 +43,6 @@ describe('Fertilize', function () { this.token = await ethers.getContractAt('TokenFacet', this.diamond.address) this.usdc = await ethers.getContractAt('IBean', USDC) this.bean = await ethers.getContractAt('IBean', BEAN) - this.well = await ethers.getContractAt('IBean', BEAN_3_CURVE) - this.weth = await ethers.getContractAt('IBean', THREE_CURVE) this.weth = await ethers.getContractAt('IBean', WETH) this.unripeBean = await ethers.getContractAt('MockToken', UNRIPE_BEAN) diff --git a/protocol/test/Stem.test.js b/protocol/test/Stem.test.js index 381975a3c7..53789aead7 100644 --- a/protocol/test/Stem.test.js +++ b/protocol/test/Stem.test.js @@ -10,6 +10,12 @@ const { upgradeWithNewFacets } = require("../scripts/diamond"); const { time, mineUpTo, mine } = require("@nomicfoundation/hardhat-network-helpers"); const { ConvertEncoder } = require('./utils/encoder.js'); const { BigNumber } = require('ethers'); +const { deployBasin } = require('../scripts/basin.js'); +const { setReserves } = require('../utils/well.js'); +const { setEthUsdPrice, setEthUsdcPrice } = require('../utils/oracle.js'); +const { impersonateEthUsdChainlinkAggregator, impersonateEthUsdcUniswap, impersonateBean, impersonateWeth } = require('../scripts/impersonate.js'); +const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); +const { finishBeanEthMigration } = require('../scripts/beanEthMigration.js'); require('dotenv').config(); let user,user2,owner; @@ -37,7 +43,6 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { } const signer = await impersonateBeanstalkOwner() - await mintEth(signer.address); await upgradeWithNewFacets({ diamondAddress: BEANSTALK, facetNames: ['EnrootFacet', 'ConvertFacet', 'WhitelistFacet', 'MockSiloFacet', 'MockSeasonFacet', 'MigrationFacet'], @@ -64,6 +69,21 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { this.unripeBean = await ethers.getContractAt('MockToken', UNRIPE_BEAN) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) this.threeCurve = await ethers.getContractAt('MockToken', THREE_CURVE); + this.well = await deployBasin(true, undefined, false, true) + + await impersonateEthUsdChainlinkAggregator() + await impersonateEthUsdcUniswap() + + await setEthUsdPrice('999.998018') + await setEthUsdcPrice('1000') + + await impersonateBean() + await impersonateWeth() + + await setReserves(owner, this.well, [to6('100001'), to18('100')]) + + await bipMigrateUnripeBean3CrvToBeanEth(true, undefined, false) + await finishBeanEthMigration() }); @@ -256,8 +276,7 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { amounts.push(newSeason); } - const depositorSigner = await impersonateSigner(depositorAddress); - await mintEth(depositorAddress); + const depositorSigner = await impersonateSigner(depositorAddress, true); await this.migrate.connect(depositorSigner).mowAndMigrate(depositorAddress, tokens, seasons, amounts, 0, 0, []); await this.silo.mow(depositorAddress, this.beanMetapool.address) }); @@ -461,8 +480,7 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { const depositorAddress = '0x5e68bb3de6133baee55eeb6552704df2ec09a824'; const token = '0x1bea3ccd22f4ebd3d37d731ba31eeca95713716d'; const stem = await this.silo.seasonToStem(token, 6061); - await mintEth(depositorAddress); - const depositorSigner = await impersonateSigner(depositorAddress); + const depositorSigner = await impersonateSigner(depositorAddress, true); await this.silo.connect(depositorSigner); await expect(this.convert.connect(depositorSigner).convert(ConvertEncoder.convertCurveLPToBeans(to6('7863'), to6('0'), this.beanMetapool.address), [stem], [to6('7863')])).to.be.revertedWith('Silo: Migration needed') }); @@ -475,13 +493,12 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { const depositorAddress = '0x10bf1dcb5ab7860bab1c3320163c6dddf8dcc0e4'; const token = '0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab'; const stem = await this.silo.seasonToStem(token, 7563); - await mintEth(depositorAddress); const threecrvHolder = '0xe74b28c2eAe8679e3cCc3a94d5d0dE83CCB84705' const threecrvSigner = await impersonateSigner(threecrvHolder); await this.threeCurve.connect(threecrvSigner).approve(this.beanMetapool.address, to18('100000000000')); await this.beanMetapool.connect(threecrvSigner).add_liquidity([to6('0'), to18('10000000')], to18('150')); - const depositorSigner = await impersonateSigner(depositorAddress); + const depositorSigner = await impersonateSigner(depositorAddress, true); await this.silo.connect(depositorSigner); await expect(this.convert.connect(depositorSigner).convert(ConvertEncoder.convertBeansToCurveLP(to6('345000'), to6('340000'), this.beanMetapool.address), [stem], [to6('345000')])).to.be.revertedWith('Silo: Migration needed') }); @@ -490,29 +507,24 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { const depositorAddress = '0x5e68bb3de6133baee55eeb6552704df2ec09a824'; const token = '0x1bea3ccd22f4ebd3d37d731ba31eeca95713716d'; const stem = await this.silo.seasonToStem(token, 6061); - await mintEth(depositorAddress); - - const depositorSigner = await impersonateSigner(depositorAddress); + const depositorSigner = await impersonateSigner(depositorAddress, true); await this.silo.connect(depositorSigner); await expect( this.convert.connect(depositorSigner).convert( - ConvertEncoder.convertUnripeLPToBeans(to6('7863'), to6('7500')), [stem], [to6('7863')])) + ConvertEncoder.convertUnripeLPToBeans(to6('7863'), '0'), [stem], [to6('7863')])) .to.be.revertedWith('Silo: Migration needed') }); it('attempt to convert unripe bean before migrating', async function () { + const reserves = await this.well.getReserves(); + await setReserves(owner, this.well, [reserves[0], reserves[1].add(to18('50'))]) + const urBean = '0x1bea0050e63e05fbb5d8ba2f10cf5800b6224449'; const stem = await this.silo.seasonToStem(urBean, 6074); const depositorAddress = '0x10bf1dcb5ab7860bab1c3320163c6dddf8dcc0e4'; - await mintEth(depositorAddress); - const depositorSigner = await impersonateSigner(depositorAddress); - - const threecrvHolder = '0xe74b28c2eAe8679e3cCc3a94d5d0dE83CCB84705' - const threecrvSigner = await impersonateSigner(threecrvHolder); - await this.threeCurve.connect(threecrvSigner).approve(this.beanMetapool.address, to18('100000000000')); - await this.beanMetapool.connect(threecrvSigner).add_liquidity([to6('0'), to18('10000000')], to18('150')); - await expect(this.convert.connect(depositorSigner).convert(ConvertEncoder.convertUnripeBeansToLP(to6('345000'), to6('340000')), [stem], [to6('345000')])).to.be.revertedWith('Silo: Migration needed') + const depositorSigner = await impersonateSigner(depositorAddress, true); + await expect(this.convert.connect(depositorSigner).convert(ConvertEncoder.convertUnripeBeansToLP(to6('345000'), to6('0')), [stem], [to6('345000')])).to.be.revertedWith('Silo: Migration needed') }); }); }); \ No newline at end of file diff --git a/protocol/test/Sun.test.js b/protocol/test/Sun.test.js index 3530728364..a03b7ba0ce 100644 --- a/protocol/test/Sun.test.js +++ b/protocol/test/Sun.test.js @@ -2,10 +2,12 @@ const { expect } = require('chai') const { deploy } = require('../scripts/deploy.js') const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot") const { to6, toStalk, toBean, to18 } = require('./utils/helpers.js'); -const { USDC, UNRIPE_LP, BEAN,ETH_USDC_UNISWAP_V3, BASE_FEE_CONTRACT, THREE_CURVE, THREE_POOL, BEAN_3_CURVE } = require('./utils/constants.js'); +const { USDC, UNRIPE_LP, BEAN,ETH_USDC_UNISWAP_V3, BASE_FEE_CONTRACT, THREE_CURVE, THREE_POOL, BEAN_3_CURVE, WETH } = require('./utils/constants.js'); const { EXTERNAL, INTERNAL } = require('./utils/balances.js'); const { ethers } = require('hardhat'); -const { deployMockWell } = require('../utils/well.js'); +const { deployMockWell, setReserves } = require('../utils/well.js'); +const { setEthUsdPrice, setEthUsdcPrice } = require('../utils/oracle.js'); +const { deployBasin } = require('../scripts/basin.js'); let user, user2, owner; let userAddress, ownerAddress, user2Address; @@ -23,6 +25,7 @@ describe('Sun', function () { this.silo = await ethers.getContractAt('MockSiloFacet', this.diamond.address) this.field = await ethers.getContractAt('MockFieldFacet', this.diamond.address) this.usdc = await ethers.getContractAt('MockToken', USDC); + this.weth = await ethers.getContractAt('MockToken', WETH); // These are needed for sunrise incentive test this.basefee = await ethers.getContractAt('MockBlockBasefee', BASE_FEE_CONTRACT); @@ -41,11 +44,16 @@ describe('Sun', function () { await this.usdc.mint(owner.address, to6('10000')) await this.bean.mint(owner.address, to6('10000')) + await this.weth.mint(owner.address, to18('10000')) await this.usdc.connect(owner).approve(this.diamond.address, to6('10000')) + await this.weth.connect(owner).approve(this.diamond.address, to18('10000')) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) await this.unripeLP.mint(owner.address, to6('10000')); - [this.well, this.wellFunction, this.pump] = await deployMockWell() + await setEthUsdPrice('999.998018'); + await setEthUsdcPrice('1000'); + + this.well = await deployBasin(true, undefined, false, true) await this.season.siloSunrise(0) }) @@ -133,7 +141,7 @@ describe('Sun', function () { it("all harvestable and all fertilizable", async function () { await this.field.incrementTotalPodsE(to6('50')); - await this.fertilizer.connect(owner).addFertilizerOwner('6274', '20', '0'); + await this.fertilizer.connect(owner).addFertilizerOwner('6274', to18('0.02'), '0'); this.result = await this.season.sunSunrise(to6('200'), 8); expect(await this.field.totalSoil()).to.be.equal('49504950'); @@ -155,7 +163,7 @@ describe('Sun', function () { it("all harvestable, some fertilizable", async function () { await this.field.incrementTotalPodsE('500'); - await this.fertilizer.connect(owner).addFertilizerOwner('0', '1', '0'); + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.001'), '0'); this.result = await this.season.sunSunrise('2000', 8); await expect(this.result).to.emit(this.season, 'Soil').withArgs(3, '495'); expect(await this.field.totalSoil()).to.be.equal('495'); @@ -179,7 +187,7 @@ describe('Sun', function () { // temperature is 1% await this.field.incrementTotalPodsE('1000'); // add 1 fertilizer owner, 1 fert (which is equal to 5 beans) - await this.fertilizer.connect(owner).addFertilizerOwner('0', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.001'), '0') //sunrise with 1500 beans 500 given to field, silo, and barn this.result = await this.season.sunSunrise('1500', 8); // emit a event that 495 soil was issued at season 3 @@ -205,9 +213,9 @@ describe('Sun', function () { it("1 all and 1 some fertilizable", async function () { await this.field.incrementTotalPodsE(to6('250')); - await this.fertilizer.connect(owner).addFertilizerOwner('0', '40', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.04'), '0') this.result = await this.season.sunSunrise(to6('120'), 8); - await this.fertilizer.connect(owner).addFertilizerOwner('6374', '40', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('6374', to18('0.04'), '0') this.result = await this.season.sunSunrise(to6('480'), 8); expect(await this.fertilizer.isFertilizing()).to.be.equal(true); @@ -250,8 +258,9 @@ describe('Sun', function () { snapshotId = await takeSnapshot(); - await this.well.setReserves(mockVal[0]); - await this.well.setReserves(mockVal[0]); + await setReserves(owner, this.well, mockVal[0]); + await setReserves(owner, this.well, mockVal[0]); + // Time skip an hour after setting new balance (twap will be very close to whats in mockVal) await timeSkip(START_TIME + 60*60); From bd4e6ed3e9f0fa43f74e78b7be511d825f8c4254 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:04:32 -0400 Subject: [PATCH 20/96] documentation + style updates --- .../beanstalk/barn/FertilizerFacet.sol | 69 ++++++++----------- .../contracts/beanstalk/barn/UnripeFacet.sol | 7 ++ .../mocks/mockFacets/MockFertilizerFacet.sol | 17 +++++ 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index ec0737c7de..71ca0bd753 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -19,7 +19,7 @@ import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; /** * @author Publius - * @title Handles Sprouting Beans from Sprout Tokens + * @title FertilizerFacet handles Minting Fertilizer and Rinsing Sprouts earned from Fertilizer. **/ contract FertilizerFacet { @@ -29,6 +29,8 @@ contract FertilizerFacet { event SetFertilizer(uint128 id, uint128 bpf); + uint256 private constant FERTILIZER_AMOUNT_PRECISION = 1e24; + AppStorage internal s; struct Supply { @@ -36,6 +38,12 @@ contract FertilizerFacet { uint256 supply; } + + /** + * @notice Rinses Rinsable Sprouts earned from Fertilizer. + * @param ids The ids of the Fertilizer to rinse. + * @param mode The balance to transfer Beans to; see {LibTrasfer.To} + */ function claimFertilized(uint256[] calldata ids, LibTransfer.To mode) external payable @@ -44,30 +52,18 @@ contract FertilizerFacet { LibTransfer.sendToken(C.bean(), amount, msg.sender, mode); } - /** - * @dev Returns the amount of Fertilize that can be purchased with `wethAmountIn` WETH. - * Can be used to help calculate `minFertilizerOut` in `mintFertilizer` - */ - function getMintFertilizerOut( - uint256 wethAmountIn - ) external view returns (uint256 fertilizerAmountOut) { - fertilizerAmountOut = wethAmountIn.mul( - LibEthUsdOracle.getEthUsdPrice() - ).div(1e24); - } - /** * @notice Purchase Fertilizer from the Barn Raise with WETH. * @param wethAmountIn Amount of WETH to buy Fertilizer with 18 decimal precision. - * @param minFertilizerOut The minimum amount of Fertilizer to purchase. - * @param minLP The minimum amount of LP to receive after. + * @param minFertilizerOut The minimum amount of Fertilizer to purchase. Protects against a significant ETH/USD price decrease. + * @param minLPTokensOut The minimum amount of LP tokens to receive after adding liquidity with `weth`. * @param mode The balance to transfer Beans to; see {LibTrasfer.To} * @dev The # of Fertilizer minted is equal to the value of the Ether paid in USD. */ function mintFertilizer( uint256 wethAmountIn, uint256 minFertilizerOut, - uint256 minLP, + uint256 minLPTokensOut, LibTransfer.From mode ) external payable returns (uint256 fertilizerAmountOut) { @@ -78,10 +74,7 @@ contract FertilizerFacet { mode ); // return value <= amount, so downcasting is safe. - // Convert from Ether amount with 18 decimals to USD amount with 0 decimals. - fertilizerAmountOut = wethAmountIn.mul( - LibEthUsdOracle.getEthUsdPrice() - ).div(1e24); + fertilizerAmountOut = getMintFertilizerOut(wethAmountIn); require(fertilizerAmountOut >= minFertilizerOut, "Fertilizer Not enough bought."); @@ -92,33 +85,14 @@ contract FertilizerFacet { uint128(s.season.current), wethAmountIn, fertilizerAmountOut, - minLP + minLPTokensOut ); C.fertilizer().beanstalkMint(msg.sender, uint256(id), (fertilizerAmountOut).toUint128(), s.bpf); } /** - * @notice Contributes to Barn Raise on behalf of existing fertilizer holders. + * @dev Callback from Fertilizer contract in `claimFertilized` function. */ - function addFertilizerOwner( - uint128 id, - uint128 amount, - uint256 minLP - ) external payable { - LibDiamond.enforceIsContractOwner(); - IERC20(C.WETH).transferFrom( - msg.sender, - address(this), - uint256(amount) - ); - - uint256 fertilizerAmount = uint256(amount).mul( - LibEthUsdOracle.getEthUsdPrice() - ).div(1e24); - - LibFertilizer.addFertilizer(id, amount, fertilizerAmount, minLP); - } - function payFertilizer(address account, uint256 amount) external payable { require(msg.sender == C.fertilizerAddress()); LibTransfer.sendToken( @@ -129,6 +103,19 @@ contract FertilizerFacet { ); } + /** + * @dev Returns the amount of Fertilize that can be purchased with `wethAmountIn` WETH. + * Can be used to help calculate `minFertilizerOut` in `mintFertilizer`. + * `wethAmountIn` has 18 decimals, `getEthUsdPrice()` has 6 decimals and `fertilizerAmountOut` has 0 decimals. + */ + function getMintFertilizerOut( + uint256 wethAmountIn + ) public view returns (uint256 fertilizerAmountOut) { + fertilizerAmountOut = wethAmountIn.mul( + LibEthUsdOracle.getEthUsdPrice() + ).div(FERTILIZER_AMOUNT_PRECISION); + } + function totalFertilizedBeans() external view returns (uint256 beans) { return s.fertilizedIndex; } diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 568d948895..15851c2f55 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -247,6 +247,13 @@ contract UnripeFacet is ReentrancyGuard { /////////////// UNDERLYING TOKEN MIGRATION ////////////////// + /** + * @notice Adds underlying tokens to an Unripe Token. + * @param unripeToken The Unripe Token to add underlying tokens to. + * @param amount The amount of underlying tokens to add. + * @dev Used to migrate the underlying token of an Unripe Token to a new token. + * Only callable by the contract owner. + */ function addMigratedUnderlying(address unripeToken, uint256 amount) external payable nonReentrant { LibDiamond.enforceIsContractOwner(); IERC20(s.u[unripeToken].underlyingToken).safeTransferFrom( diff --git a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol index 0bc9a6036a..146b631857 100644 --- a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol +++ b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol @@ -14,6 +14,23 @@ import "contracts/beanstalk/barn/FertilizerFacet.sol"; contract MockFertilizerFacet is FertilizerFacet { + function addFertilizerOwner( + uint128 id, + uint128 wethAmountIn, + uint256 minLPOut + ) external payable { + LibDiamond.enforceIsContractOwner(); + IERC20(C.WETH).transferFrom( + msg.sender, + address(this), + uint256(wethAmountIn) + ); + + uint256 fertilizerAmount = getMintFertilizerOut(wethAmountIn); + + LibFertilizer.addFertilizer(id, wethAmountIn, fertilizerAmount, minLPOut); + } + function setPenaltyParams(uint256 recapitalized, uint256 fertilized) external { s.recapitalized = recapitalized; s.fertilizedIndex = fertilized; From 011576743b78143ee943958371f7dd66f3e5b898 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:08:15 -0400 Subject: [PATCH 21/96] remove addFertilizerOwner function --- protocol/scripts/bips.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/protocol/scripts/bips.js b/protocol/scripts/bips.js index 07db151aaf..b9a2bb19cd 100644 --- a/protocol/scripts/bips.js +++ b/protocol/scripts/bips.js @@ -160,7 +160,10 @@ async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefine "ConvertGettersFacet" ], initFacetName: "InitMigrateUnripeBean3CrvToBeanEth", - selectorsToRemove: [ '0x0bfca7e3' ], + selectorsToRemove: [ + '0x0bfca7e3', + '0x8cd31ca0' + ], bip: false, object: !mock, verbose: verbose, From af59a90e89e13051af20cad38d33e3aac3f0946f Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:19:40 -0400 Subject: [PATCH 22/96] update ABI --- protocol/abi/Beanstalk.json | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/protocol/abi/Beanstalk.json b/protocol/abi/Beanstalk.json index 1e59bd6d06..2bac5dc7df 100644 --- a/protocol/abi/Beanstalk.json +++ b/protocol/abi/Beanstalk.json @@ -516,29 +516,6 @@ "name": "SetFertilizer", "type": "event" }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "id", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" - }, - { - "internalType": "uint256", - "name": "minLP", - "type": "uint256" - } - ], - "name": "addFertilizerOwner", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, { "inputs": [ { @@ -883,7 +860,7 @@ }, { "internalType": "uint256", - "name": "minLP", + "name": "minLPTokensOut", "type": "uint256" }, { From 1bdf75c7181374d9436520be328c58a1917ab3b7 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:30:41 -0400 Subject: [PATCH 23/96] transfer WETH directly to Well --- .../contracts/beanstalk/barn/FertilizerFacet.sol | 13 +++++++------ protocol/contracts/libraries/LibFertilizer.sol | 10 ++-------- .../mocks/mockFacets/MockFertilizerFacet.sol | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index 71ca0bd753..1555d2c5a5 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -66,13 +66,15 @@ contract FertilizerFacet { uint256 minLPTokensOut, LibTransfer.From mode ) external payable returns (uint256 fertilizerAmountOut) { - - wethAmountIn = LibTransfer.receiveToken( + // Transfer the WETH directly to the Well for gas efficiency purposes. + wethAmountIn = LibTransfer.transferToken( IERC20(C.WETH), - uint256(wethAmountIn), msg.sender, - mode - ); // return value <= amount, so downcasting is safe. + C.BEAN_ETH_WELL, + uint256(wethAmountIn), + mode, + LibTransfer.To.EXTERNAL + ); fertilizerAmountOut = getMintFertilizerOut(wethAmountIn); @@ -83,7 +85,6 @@ contract FertilizerFacet { uint128 id = LibFertilizer.addFertilizer( uint128(s.season.current), - wethAmountIn, fertilizerAmountOut, minLPTokensOut ); diff --git a/protocol/contracts/libraries/LibFertilizer.sol b/protocol/contracts/libraries/LibFertilizer.sol index f59cbfb6ea..718c0687a2 100644 --- a/protocol/contracts/libraries/LibFertilizer.sol +++ b/protocol/contracts/libraries/LibFertilizer.sol @@ -35,7 +35,6 @@ library LibFertilizer { function addFertilizer( uint128 season, - uint256 amount, uint256 fertilizerAmount, uint256 minLP ) internal returns (uint128 id) { @@ -54,7 +53,7 @@ library LibFertilizer { s.fertilizer[id] = s.fertilizer[id].add(fertilizerAmount128); s.activeFertilizer = s.activeFertilizer.add(fertilizerAmount); // Add underlying to Unripe Beans and Unripe LP - addUnderlying(amount, fertilizerAmount.mul(DECIMALS), minLP); + addUnderlying(fertilizerAmount.mul(DECIMALS), minLP); // If not first time adding Fertilizer with this id, return if (s.fertilizer[id] > fertilizerAmount128) return id; // If first time, log end Beans Per Fertilizer and add to Season queue. @@ -73,7 +72,7 @@ library LibFertilizer { humidity = RESTART_HUMIDITY.sub(humidityDecrease); } - function addUnderlying(uint256 amount, uint256 usdAmount, uint256 minAmountOut) internal { + function addUnderlying(uint256 usdAmount, uint256 minAmountOut) internal { AppStorage storage s = LibAppStorage.diamondStorage(); // Calculate how many new Deposited Beans will be minted uint256 percentToFill = usdAmount.mul(C.precision()).div( @@ -106,11 +105,6 @@ library LibFertilizer { newDepositedLPBeans ); - IERC20(C.WETH).transfer( - address(C.BEAN_ETH_WELL), - amount - ); - uint256 newLP = IWell(C.BEAN_ETH_WELL).sync( address(this), minAmountOut diff --git a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol index 146b631857..122f0a7104 100644 --- a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol +++ b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol @@ -22,13 +22,13 @@ contract MockFertilizerFacet is FertilizerFacet { LibDiamond.enforceIsContractOwner(); IERC20(C.WETH).transferFrom( msg.sender, - address(this), + C.BEAN_ETH_WELL, uint256(wethAmountIn) ); uint256 fertilizerAmount = getMintFertilizerOut(wethAmountIn); - LibFertilizer.addFertilizer(id, wethAmountIn, fertilizerAmount, minLPOut); + LibFertilizer.addFertilizer(id, fertilizerAmount, minLPOut); } function setPenaltyParams(uint256 recapitalized, uint256 fertilized) external { From 1d5a628ed33d4192dcdc3385f82bb97880728cee Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:35:51 -0400 Subject: [PATCH 24/96] add comment to --- protocol/contracts/libraries/LibFertilizer.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protocol/contracts/libraries/LibFertilizer.sol b/protocol/contracts/libraries/LibFertilizer.sol index 718c0687a2..356941d794 100644 --- a/protocol/contracts/libraries/LibFertilizer.sol +++ b/protocol/contracts/libraries/LibFertilizer.sol @@ -72,6 +72,10 @@ library LibFertilizer { humidity = RESTART_HUMIDITY.sub(humidityDecrease); } + /** + * @dev Any WETH contributions should already be transferred to the Bean:Eth Well to allow for a gas efficient liquidity + * addition through the use of `sync`. See {FertilizerFacet.mintFertilizer} for an example. + */ function addUnderlying(uint256 usdAmount, uint256 minAmountOut) internal { AppStorage storage s = LibAppStorage.diamondStorage(); // Calculate how many new Deposited Beans will be minted From cdc38f6d40cc4fb082bc6fe102628b93841eba8e Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:39:30 -0400 Subject: [PATCH 25/96] update comments --- protocol/contracts/beanstalk/barn/FertilizerFacet.sol | 2 +- protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index 1555d2c5a5..2a7ab72161 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -66,7 +66,7 @@ contract FertilizerFacet { uint256 minLPTokensOut, LibTransfer.From mode ) external payable returns (uint256 fertilizerAmountOut) { - // Transfer the WETH directly to the Well for gas efficiency purposes. + // Transfer the WETH directly to the Well for gas efficiency purposes. The WETH is later synced in {LibFertilizer.addUnderlying}. wethAmountIn = LibTransfer.transferToken( IERC20(C.WETH), msg.sender, diff --git a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol index 122f0a7104..392e6adf44 100644 --- a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol +++ b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol @@ -20,6 +20,7 @@ contract MockFertilizerFacet is FertilizerFacet { uint256 minLPOut ) external payable { LibDiamond.enforceIsContractOwner(); + // Transfer the WETH directly to the Well for gas efficiency purposes. The WETH is later synced in {LibFertilizer.addUnderlying}. IERC20(C.WETH).transferFrom( msg.sender, C.BEAN_ETH_WELL, From 3c69f7ef34fd4329a65c3c4040132e441ea23215 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 22:06:35 -0400 Subject: [PATCH 26/96] add tests to demonstrate success after migration --- .../test/Bean3CrvToBeanEthMigration.test.js | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/protocol/test/Bean3CrvToBeanEthMigration.test.js b/protocol/test/Bean3CrvToBeanEthMigration.test.js index 5970679f8f..89ad56cbbd 100644 --- a/protocol/test/Bean3CrvToBeanEthMigration.test.js +++ b/protocol/test/Bean3CrvToBeanEthMigration.test.js @@ -7,10 +7,11 @@ const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); const { getBeanstalk } = require('../utils/contracts.js'); const { impersonateBeanstalkOwner, impersonateSigner } = require('../utils/signer.js'); const { ethers } = require('hardhat'); -const { mintEth } = require('../utils/mint.js'); +const { mintEth, mintBeans } = require('../utils/mint.js'); const { ConvertEncoder } = require('./utils/encoder.js'); const { setReserves } = require('../utils/well.js'); const { toBN } = require('../utils/helpers.js'); +const { impersonateBean } = require('../scripts/impersonate.js'); let user,user2,owner; let publius; @@ -145,5 +146,37 @@ describe('Bean:3Crv to Bean:Eth Migration', function () { expect(await this.beanstalk.getTotalUnderlying(UNRIPE_LP)).to.be.equal(beanEthUnderlying) expect(await this.beanstalk.getUnderlying(UNRIPE_LP, await this.unripeLp.totalSupply())).to.be.equal(beanEthUnderlying) }) + + describe('Interactions with Unripe succeed', async function () { + it('chop succeeds', async function () { + await this.beanstalk.connect(publius).withdrawDeposit(UNRIPE_LP, '-56836', to6('1'), 1); + await this.beanstalk.connect(publius).chop(UNRIPE_LP, to6('1'), 1, 0); + }) + + it('deposit succeeds', async function () { + await this.beanstalk.connect(publius).withdrawDeposit(UNRIPE_LP, '-56836', to6('1'), 1); + await this.beanstalk.connect(publius).deposit(UNRIPE_LP, to6('1'), 1); + }) + + it('enrootDeposit succeeds', async function () { + await this.beanstalk.connect(publius).enrootDeposit(UNRIPE_LP, '-56836', to6('1')); + }) + + it('enrootDeposits succeeds', async function () { + await this.beanstalk.connect(publius).enrootDeposits(UNRIPE_LP, ['-56836'], [to6('1')]); + }) + + it('convert Unripe Bean to LP succeeds', async function () { + await this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['-16272'], [to6('200')]); + }) + + it('convert Unripe LP to Bean succeeds', async function () { + await impersonateBean() + await this.bean.mint(user.address, to6('100000')) + await this.bean.connect(user).approve(BEAN_ETH_WELL, to6('100000')) + await this.beanEth.connect(user).addLiquidity([to6('100000'), '0'], '0', user.address, ethers.constants.MaxUint256); + await this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeLPToBeans(to6('200'), '0'), ['-56836'], [to6('200')]) + }) + }) }) }) \ No newline at end of file From 12c608a22535e3a1fe379db1153185fe43851ea7 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 22:33:48 -0400 Subject: [PATCH 27/96] more convert tests --- protocol/test/ConvertUnripe.test.js | 120 ++++++++++++++-------------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/protocol/test/ConvertUnripe.test.js b/protocol/test/ConvertUnripe.test.js index d77e2e8c74..decc0a243e 100644 --- a/protocol/test/ConvertUnripe.test.js +++ b/protocol/test/ConvertUnripe.test.js @@ -54,7 +54,7 @@ describe('Unripe Convert', function () { await this.wellToken.connect(user2).approve(this.silo.address, ethers.constants.MaxUint256); await this.well.connect(user).addLiquidity( - [toBean('10000'), to18('10')], + [toBean('1000000'), to18('1000')], 0, owner.address, ethers.constants.MaxUint256 @@ -65,7 +65,7 @@ describe('Unripe Convert', function () { this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) this.fertilizer = await ethers.getContractAt('MockFertilizerFacet', this.diamond.address) await this.unripeBean.mint(userAddress, to6('10000')) - await this.unripeLP.mint(userAddress, to6('31.622776')) + await this.unripeLP.mint(userAddress, to6('3162.277660')) await this.unripeBean.connect(user).approve(this.diamond.address, to18('100000000')) await this.unripeLP.connect(user).approve(this.diamond.address, to18('100000000')) await this.fertilizer.setFertilizerE(true, to6('10000')) @@ -79,7 +79,7 @@ describe('Unripe Convert', function () { ) await this.unripe.connect(owner).addUnderlying( UNRIPE_LP, - to18('31.622776') // 31.622776601683793319 + to18('3162.277660') // 3162.2776601683793319 ) }); @@ -139,7 +139,7 @@ describe('Unripe Convert', function () { user.address, ethers.constants.MaxUint256 ); - expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal(to6('30.182395')); + expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal(to6('31.606981')); }); }) @@ -188,29 +188,29 @@ describe('Unripe Convert', function () { it('properly updates total values', async function () { expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1000')); expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('474652298'); - const bdv = await this.silo.bdv(this.unripeLP.address, '474652298') + expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('4711829'); + const bdv = await this.silo.bdv(this.unripeLP.address, '4711829') expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(bdv); expect(await this.silo.totalStalk()).to.eq(toStalk('100').add(bdv.mul(to6('0.01')))); }); it('properly updates user values -test', async function () { - const bdv = await this.silo.bdv(this.unripeLP.address, '474652298') + const bdv = await this.silo.bdv(this.unripeLP.address, '4711829') expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('100').add(bdv.mul(to6('0.01')))); }); it('properly updates user deposits', async function () { expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1000')); const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); - expect(deposit[0]).to.eq('474652298'); - expect(deposit[1]).to.eq(await this.silo.bdv(this.unripeLP.address, '474652298')); + expect(deposit[0]).to.eq('4711829'); + expect(deposit[1]).to.eq(await this.silo.bdv(this.unripeLP.address, '4711829')); }); it('emits events', async function () { await expect(this.result).to.emit(this.silo, 'RemoveDeposits') .withArgs(userAddress, this.unripeBean.address, [0], [to6('1000')], to6('1000'), [to6('100')]); await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 0, '474652298', await this.silo.bdv(this.unripeLP.address, '474652298')); + .withArgs(userAddress, this.unripeLP.address, 0, '4711829', await this.silo.bdv(this.unripeLP.address, '4711829')); }); }); @@ -361,59 +361,61 @@ describe('Unripe Convert', function () { // }) }); -// describe('convert lp to beans', async function () { -// beforeEach(async function () { -// await this.season.teleportSunrise(10); -// this.season.deployStemsUpgrade(); -// }); + describe('convert lp to beans', async function () { + beforeEach(async function () { + await this.season.teleportSunrise(10); + this.season.deployStemsUpgrade(); + }); -// describe('revert', async function () { -// it('not enough Beans', async function () { -// await this.well.connect(user).addLiquidity( -// [toBean('200'), '0'], -// '0', -// user.address, -// ethers.constants.MaxUint256 -// ); -// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); -// await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) -// .to.be.revertedWith('Curve: Insufficient Output'); -// }); + describe('revert', async function () { + it('not enough Beans', async function () { + await this.well.connect(user).addLiquidity( + [toBean('200'), '0'], + '0', + user.address, + ethers.constants.MaxUint256 + ); + await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); + await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) + .to.be.revertedWith(''); + }); -// it('p >= 1', async function () { -// await this.well.connect(user).addLiquidity([toBean('0'), to18('1')], to18('0.5')); -// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); -// await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) -// .to.be.revertedWith('Convert: P must be < 1.'); -// }); -// }); + it('p >= 1', async function () { + await this.well.connect(user).addLiquidity([toBean('0'), to18('1')], to18('0.5'), user.address, ethers.constants.MaxUint256); + await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); + await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) + .to.be.revertedWith('Convert: P must be < 1.'); + }); + }); -// describe('below max', function () { -// beforeEach(async function () { -// await this.well.connect(user).addLiquidity( -// [toBean('200'), '0'], -// '0', -// user.address, -// ethers.constants.MaxUint256 -// ); -// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); -// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990')), ['0'], [to6('1000')]) -// }); + describe('below max', function () { + beforeEach(async function () { + await this.well.connect(user).addLiquidity( + [toBean('200'), '0'], + '0', + user.address, + ethers.constants.MaxUint256 + ); + await this.silo.connect(user).deposit(this.unripeLP.address, to6('3'), EXTERNAL); + this.bdv = await this.silo.getTotalDepositedBdv(this.unripeLP.address); + this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('3'), toBN('0')), ['0'], [to6('1000')]) + }); -// it('properly updates total values', async function () { -// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); -// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); -// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); -// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); -// //expect(await this.silo.totalSeeds()).to.eq(to6('201.236334')); -// expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); -// }); + it('properly updates total values', async function () { + const bdv = await this.silo.bdv(this.unripeBean.address, '636776401') + expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq('636776401'); + expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(this.bdv); + expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); + expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); + //expect(await this.silo.totalSeeds()).to.eq(to6('201.236334')); + expect(await this.silo.totalStalk()).to.eq(this.bdv.mul('10000')); + }); -// it('properly updates user values', async function () { -// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('201.236334')); -// expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); -// }); -// }); + it('properly updates user values', async function () { + //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('201.236334')); + expect(await this.silo.totalStalk()).to.eq(this.bdv.mul('10000')); + }); + }); // //these tests use the new 2 seeds per bdv instead of previous 4 (note in the beforeEach above that deployStemsUpgrade is called) // describe('multiple crates', function () { @@ -522,5 +524,5 @@ describe('Unripe Convert', function () { // expect(await this.silo.totalStalk()).to.eq(toStalk('200')); // }); // }); -// }); + }); }); From bddb296cb51928b4b017e0009e9a0f00c635a29f Mon Sep 17 00:00:00 2001 From: Brean0 Date: Mon, 18 Sep 2023 20:05:18 +0900 Subject: [PATCH 28/96] change metadata - add urBEANETH support - remove urBEAN3CRV - rename deposit token names to better standardize --- projects/ui/src/graph/graphql.schema.json | 3038 ++++++++++++++++- .../beanstalk/metadata/MetadataImage.sol | 66 +- protocol/test/data/base64EncodedImageBean.txt | 2 +- .../test/data/base64EncodedImageBean3Crv.txt | 2 +- .../test/data/base64EncodedImageBeanEth.txt | 2 +- .../test/data/base64EncodedImageUrBean.txt | 2 +- .../data/base64EncodedImageUrBean3Crv.txt | 1 - .../data/base64EncodedImageUrBean3Crv2.txt | 1 - .../test/data/base64EncodedImageUrBeanEth.txt | 1 + 9 files changed, 3071 insertions(+), 44 deletions(-) delete mode 100644 protocol/test/data/base64EncodedImageUrBean3Crv.txt delete mode 100644 protocol/test/data/base64EncodedImageUrBean3Crv2.txt create mode 100644 protocol/test/data/base64EncodedImageUrBeanEth.txt diff --git a/projects/ui/src/graph/graphql.schema.json b/projects/ui/src/graph/graphql.schema.json index 0cbf867354..5a41d47910 100644 --- a/projects/ui/src/graph/graphql.schema.json +++ b/projects/ui/src/graph/graphql.schema.json @@ -16572,6 +16572,22 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "overall", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "pool", "description": null, @@ -17436,6 +17452,70 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "overall", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "overall_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "overall_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "overall_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "pool", "description": null, @@ -18817,6 +18897,12 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "overall", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "pool", "description": null, @@ -105134,6 +105220,176 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "wellOracle", + "description": null, + "args": [ + { + "name": "block", + "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "type": { + "kind": "INPUT_OBJECT", + "name": "Block_height", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subgraphError", + "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "_SubgraphErrorPolicy_", + "ofType": null + } + }, + "defaultValue": "deny", + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "wellOracles", + "description": null, + "args": [ + { + "name": "block", + "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "type": { + "kind": "INPUT_OBJECT", + "name": "Block_height", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "100", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "orderBy", + "description": null, + "type": { + "kind": "ENUM", + "name": "WellOracle_orderBy", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "orderDirection", + "description": null, + "type": { + "kind": "ENUM", + "name": "OrderDirection", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "skip", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "0", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subgraphError", + "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "_SubgraphErrorPolicy_", + "ofType": null + } + }, + "defaultValue": "deny", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "where", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "whitelistToken", "description": null, @@ -125251,6 +125507,11 @@ "name": "StalkChange", "ofType": null }, + { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + }, { "kind": "OBJECT", "name": "WhitelistToken", @@ -130817,9 +131078,41 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "fourPointFiveSeedBeanAPY", + "description": "Bean APY for 4.5 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY", + "description": "Stalk APY for 4.5 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "fourSeedBeanAPY", - "description": "Bean APY for four seeds per BDV", + "description": "Bean APY for 4 seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -130835,7 +131128,7 @@ }, { "name": "fourSeedStalkAPY", - "description": "Stalk APY for four seeds per BDV", + "description": "Stalk APY for 4 seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -130881,9 +131174,73 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "threePointTwoFiveSeedBeanAPY", + "description": "Bean APY for 3.25 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY", + "description": "Stalk APY for 3.25 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY", + "description": "Bean APY for 3 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY", + "description": "Stalk APY for 3 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "twoSeedBeanAPY", - "description": "Bean APY for two seeds per BDV", + "description": "Bean APY for 2 seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -130899,7 +131256,7 @@ }, { "name": "twoSeedStalkAPY", - "description": "Stalk APY for two seeds per BDV", + "description": "Stalk APY for 2 seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -130928,6 +131285,22 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY", + "description": "Bean APY for 0 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -131305,6 +131678,230 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "fourPointFiveSeedBeanAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "fourSeedBeanAPY", "description": null, @@ -131769,6 +132366,454 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "threePointTwoFiveSeedBeanAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "twoSeedBeanAPY", "description": null, @@ -132104,6 +133149,118 @@ "defaultValue": null, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null } ], "interfaces": null, @@ -132136,6 +133293,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "fourPointFiveSeedBeanAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "fourSeedBeanAPY", "description": null, @@ -132160,6 +133329,30 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "threePointTwoFiveSeedBeanAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "twoSeedBeanAPY", "description": null, @@ -132177,6 +133370,12 @@ "description": null, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null } ], "possibleTypes": null @@ -147108,6 +148307,176 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "wellOracle", + "description": null, + "args": [ + { + "name": "block", + "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "type": { + "kind": "INPUT_OBJECT", + "name": "Block_height", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subgraphError", + "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "_SubgraphErrorPolicy_", + "ofType": null + } + }, + "defaultValue": "deny", + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "wellOracles", + "description": null, + "args": [ + { + "name": "block", + "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "type": { + "kind": "INPUT_OBJECT", + "name": "Block_height", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "100", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "orderBy", + "description": null, + "type": { + "kind": "ENUM", + "name": "WellOracle_orderBy", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "orderDirection", + "description": null, + "type": { + "kind": "ENUM", + "name": "OrderDirection", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "skip", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "0", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subgraphError", + "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "_SubgraphErrorPolicy_", + "ofType": null + } + }, + "defaultValue": "deny", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "where", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "whitelistToken", "description": null, @@ -148967,6 +150336,1667 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "WellOracle", + "description": null, + "fields": [ + { + "name": "blockNumber", + "description": " Block number of this event ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt", + "description": " Timestamp of this event ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves", + "description": " Time weighted cumulative reserves ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB", + "description": " DeltaB for season", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash", + "description": " Transaction hash of the transaction that emitted this event ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": "wellOracle-{ Transaction hash }-{ Log index }", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex", + "description": " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol", + "description": " The protocol this transaction belongs to ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Beanstalk", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season", + "description": " Season of oracle ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "SiloEvent", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "_change_block", + "description": "Filter for the block changed event.", + "type": { + "kind": "INPUT_OBJECT", + "name": "BlockChangedFilter", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "and", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_not_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_contains_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_ends_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_ends_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_contains_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_ends_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_ends_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_starts_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_starts_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_starts_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_starts_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "or", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "Beanstalk_filter", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_contains_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_ends_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_ends_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_contains_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_ends_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_ends_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_starts_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_starts_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_starts_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_starts_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "WellOracle_orderBy", + "description": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "blockNumber", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__id", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__lastSeason", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__lastUpgrade", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__methodologyVersion", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__name", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__schemaVersion", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__slug", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__subgraphVersion", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season", + "description": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, { "kind": "OBJECT", "name": "WhitelistToken", diff --git a/protocol/contracts/beanstalk/metadata/MetadataImage.sol b/protocol/contracts/beanstalk/metadata/MetadataImage.sol index 0977878f5b..8e7989c67f 100644 --- a/protocol/contracts/beanstalk/metadata/MetadataImage.sol +++ b/protocol/contracts/beanstalk/metadata/MetadataImage.sol @@ -71,8 +71,8 @@ contract MetadataImage { beanToken(), bean3CRVToken(), urBeanToken(), - urBean3CRVToken(), beanETHCP2WellToken(), + urBeanETHCP2WellToken(), fullLeafRow(), '' )); @@ -409,36 +409,22 @@ contract MetadataImage { return beanTemplateToken(false); } - function bean3CRVToken() internal pure returns (string memory) { - return beanLPTemplateToken(false); - } - function urBeanToken() internal pure returns (string memory) { return beanTemplateToken(true); } - function urBean3CRVToken() internal pure returns (string memory) { - return beanLPTemplateToken(true); + function beanETHCP2WellToken() internal pure returns (string memory) { + return beanETHCP2WellTemplateToken(false); } - function beanTemplateToken(bool ripe) internal pure returns (string memory) { - return string(abi.encodePacked( - '', - '' - ) - ); + function urBeanETHCP2WellToken() internal pure returns (string memory) { + return beanETHCP2WellTemplateToken(true); } - function beanLPTemplateToken(bool ripe) internal pure returns (string memory) { + function bean3CRVToken() internal pure returns (string memory) { return string(abi.encodePacked( - '', '', '', @@ -448,21 +434,33 @@ contract MetadataImage { '' ) ); - } + } - function beanETHCP2WellToken() internal pure returns (string memory) { + function beanTemplateToken(bool ripe) internal pure returns (string memory) { + return string(abi.encodePacked( + '', + '' + ) + ); + } + + function beanETHCP2WellTemplateToken(bool ripe) internal pure returns (string memory) { return string(abi.encodePacked( - '', - '', - '', - '', + '', '', '' ) ); } - function useAssetTransform(string memory assetName, int256 x, int256 y) internal pure returns (string memory) { return string(abi.encodePacked( ' Date: Mon, 18 Sep 2023 20:06:18 +0900 Subject: [PATCH 29/96] update tests --- protocol/test/Silo.test.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/protocol/test/Silo.test.js b/protocol/test/Silo.test.js index 3538c5057a..0bce531ab6 100644 --- a/protocol/test/Silo.test.js +++ b/protocol/test/Silo.test.js @@ -362,28 +362,28 @@ describe('Silo', function () { it("properly gives an URI", async function () { await this.season.farmSunrises(1000); + // bean token depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBean.txt', 'utf-8'); depositID1 = '0xBEA0000029AD1c77D3d5D23Ba2D8893dB9d1Efab000000000000000000000002'; expect(await this.metadata.uri(depositID1)).to.eq(depositmetadata); + // bean3crv token depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBean3Crv.txt', 'utf-8'); depositID2 = '0xC9C32CD16BF7EFB85FF14E0C8603CC90F6F2EE49000000000000000000000200'; expect(await this.metadata.uri(depositID2)).to.eq(depositmetadata); - depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBean.txt', 'utf-8'); - depositID3 = '0x1BEA0050E63e05FBb5D8BA2f10cf5800B6224449000000000000000000000400'; + // beanEthToken + depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBeanEth.txt', 'utf-8'); + depositID3 = '0xBEA0e11282e2bB5893bEcE110cF199501e872bAdFFFFFFFFFFFFF00000000002'; expect(await this.metadata.uri(depositID3)).to.eq(depositmetadata); - - depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBean3Crv.txt', 'utf-8'); - depositID4 = '0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716DFFFFFFFFFFFFFFFFFFFFF97C'; - expect(await this.metadata.uri(depositID4)).to.eq(depositmetadata); - - depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBean3Crv2.txt', 'utf-8'); - depositID4 = '0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716DFFF000000000000000000111'; + // urBean token + depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBean.txt', 'utf-8'); + depositID4 = '0x1BEA0050E63e05FBb5D8BA2f10cf5800B6224449000000000000000000000400'; expect(await this.metadata.uri(depositID4)).to.eq(depositmetadata); - depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBeanEth.txt', 'utf-8'); - depositID5 = '0xBEA0e11282e2bB5893bEcE110cF199501e872bAdFFFFFFFFFFFFF00000000002'; + // urBeanEth token + depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBeanEth.txt', 'utf-8'); + depositID5 = '0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716DFFFFFFFFFFFFFFFFFFFFF97C'; expect(await this.metadata.uri(depositID5)).to.eq(depositmetadata); }); From 853cace32fc74142f3b8a0260bac653a62ef1bc8 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 18 Sep 2023 11:50:18 -0400 Subject: [PATCH 30/96] Add SwitchUnderlyingToken event and switchUnderlyingToken function --- protocol/abi/Beanstalk.json | 37 +++++++++++++++++++ protocol/contracts/C.sol | 4 +- .../contracts/beanstalk/barn/UnripeFacet.sol | 14 +++++++ .../InitMigrateUnripeBean3CrvToBeanEth.sol | 2 +- protocol/contracts/libraries/LibUnripe.sol | 11 ++++++ 5 files changed, 65 insertions(+), 3 deletions(-) diff --git a/protocol/abi/Beanstalk.json b/protocol/abi/Beanstalk.json index 2bac5dc7df..d9f419d093 100644 --- a/protocol/abi/Beanstalk.json +++ b/protocol/abi/Beanstalk.json @@ -99,6 +99,25 @@ "name": "Pick", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "underlyingToken", + "type": "address" + } + ], + "name": "SwitchUnderlyingToken", + "type": "event" + }, { "inputs": [ { @@ -497,6 +516,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "unripeToken", + "type": "address" + }, + { + "internalType": "address", + "name": "newUnderlyingToken", + "type": "address" + } + ], + "name": "switchUnderlyingToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "anonymous": false, "inputs": [ diff --git a/protocol/contracts/C.sol b/protocol/contracts/C.sol index 569df18015..cdfcec97e7 100644 --- a/protocol/contracts/C.sol +++ b/protocol/contracts/C.sol @@ -78,8 +78,8 @@ library C { //////////////////// Well //////////////////// uint256 internal constant WELL_MINIMUM_BEAN_BALANCE = 1000_000_000; // 1,000 Beans - address constant internal BEANSTALK_PUMP = 0xBA510f10E3095B83a0F33aa9ad2544E22570a87C; - address constant BEAN_ETH_WELL = 0xBEA0e11282e2bB5893bEcE110cF199501e872bAd; + address internal constant BEANSTALK_PUMP = 0xBA510f10E3095B83a0F33aa9ad2544E22570a87C; + address internal constant BEAN_ETH_WELL = 0xBEA0e11282e2bB5893bEcE110cF199501e872bAd; function getSeasonPeriod() internal pure returns (uint256) { return CURRENT_SEASON_PERIOD; diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 15851c2f55..63f79ddb10 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -35,6 +35,8 @@ contract UnripeFacet is ReentrancyGuard { event ChangeUnderlying(address indexed token, int256 underlying); + event SwitchUnderlyingToken(address indexed token, address indexed underlyingToken); + event Chop( address indexed account, address indexed token, @@ -263,4 +265,16 @@ contract UnripeFacet is ReentrancyGuard { ); LibUnripe.incrementUnderlying(unripeToken, amount); } + + /** + * @notice Switches the Underlying Token of an Unripe Token. + * @param unripeToken The Unripe Token to switch the underlying token of. + * @param newUnderlyingToken The new underlying token to switch to. + * @dev `s.u[unripeToken].balanceOfUnderlying` must be 0. + */ + function switchUnderlyingToken(address unripeToken, address newUnderlyingToken) external payable { + LibDiamond.enforceIsContractOwner(); + require(s.u[unripeToken].balanceOfUnderlying == 0, "Unripe: Underlying balance > 0"); + LibUnripe.switchUnderlyingToken(unripeToken, newUnderlyingToken); + } } diff --git a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol index 8b1d77b910..b4ebadd749 100644 --- a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol +++ b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol @@ -26,6 +26,6 @@ contract InitMigrateUnripeBean3CrvToBeanEth { balanceOfUnderlying ); LibUnripe.decrementUnderlying(C.UNRIPE_LP, balanceOfUnderlying); - s.u[C.UNRIPE_LP].underlyingToken = C.BEAN_ETH_WELL; + LibUnripe.switchUnderlyingToken(C.UNRIPE_LP, C.BEAN_ETH_WELL); } } \ No newline at end of file diff --git a/protocol/contracts/libraries/LibUnripe.sol b/protocol/contracts/libraries/LibUnripe.sol index d1ec2a1195..66744070b2 100644 --- a/protocol/contracts/libraries/LibUnripe.sol +++ b/protocol/contracts/libraries/LibUnripe.sol @@ -16,6 +16,7 @@ library LibUnripe { using SafeMath for uint256; event ChangeUnderlying(address indexed token, int256 underlying); + event SwitchUnderlyingToken(address indexed token, address indexed underlyingToken); uint256 constant DECIMALS = 1e6; @@ -94,4 +95,14 @@ library LibUnripe { } decrementUnderlying(token, underlying); } + + /** + * @dev Switches the underlying token of an unripe token. + * Should only be called if `s.u[unripeToken].balanceOfUnderlying == 0`. + */ + function switchUnderlyingToken(address unripeToken, address newUnderlyingToken) internal { + AppStorage storage s = LibAppStorage.diamondStorage(); + s.u[unripeToken].underlyingToken = newUnderlyingToken; + emit SwitchUnderlyingToken(unripeToken, newUnderlyingToken); + } } From 64d781e0cdd09463e5d5c85a7be936615b66a055 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 18 Sep 2023 11:50:42 -0400 Subject: [PATCH 31/96] Add switch underlying token tests --- protocol/test/Unripe.test.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/protocol/test/Unripe.test.js b/protocol/test/Unripe.test.js index 0d71d638ad..b72df042c2 100644 --- a/protocol/test/Unripe.test.js +++ b/protocol/test/Unripe.test.js @@ -2,7 +2,7 @@ const { expect } = require('chai') const { EXTERNAL, INTERNAL, INTERNAL_EXTERNAL, INTERNAL_TOLERANT } = require('./utils/balances.js') const { deploy } = require('../scripts/deploy.js') const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot") -const { BEAN, UNRIPE_BEAN, UNRIPE_LP } = require('./utils/constants') +const { BEAN, UNRIPE_BEAN, UNRIPE_LP, USDT } = require('./utils/constants') const { to6, to18, toStalk } = require('./utils/helpers.js') const ZERO_BYTES = ethers.utils.formatBytes32String('0x0') @@ -203,4 +203,27 @@ describe('Unripe', function () { ) }) }) + + describe('change underlying', async function () { + it('changes underlying token', async function () { + this.result = await this.unripe.connect(owner).switchUnderlyingToken(UNRIPE_BEAN, USDT) + expect(await this.unripe.getUnderlyingToken(UNRIPE_BEAN)).to.be.equal(USDT) + await expect(this.result).to.emit(this.unripe, 'SwitchUnderlyingToken').withArgs( + UNRIPE_BEAN, + USDT + ) + }) + + it('reverts if underlying balance > 0', async function () { + await this.unripe.connect(owner).addUnderlying( + UNRIPE_BEAN, + to6('100') + ) + await expect(this.unripe.connect(owner).switchUnderlyingToken(UNRIPE_BEAN, USDT)).to.be.revertedWith('Unripe: Underlying balance > 0') + }) + + it('reverts if not owner', async function () { + await expect(this.unripe.connect(user).switchUnderlyingToken(UNRIPE_BEAN, USDT)).to.be.revertedWith('LibDiamond: Must be contract owner') + }) + }) }) \ No newline at end of file From a150d8773e5471be014ff16932b7f3f0c5ca7096 Mon Sep 17 00:00:00 2001 From: alecks <0xalecks@gmail.com> Date: Wed, 20 Sep 2023 10:09:42 -0400 Subject: [PATCH 32/96] protocol: add bip38 migration script --- protocol/hardhat.config.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/protocol/hardhat.config.js b/protocol/hardhat.config.js index 7513790a17..5aa013e896 100644 --- a/protocol/hardhat.config.js +++ b/protocol/hardhat.config.js @@ -12,6 +12,11 @@ require("@openzeppelin/hardhat-upgrades"); require("dotenv").config(); require("hardhat-contract-sizer"); +// BIP 38 migration ---- +const { bipMigrateUnripeBean3CrvToBeanEth } = require("./scripts/bips.js"); +const { finishBeanEthMigration } = require("./scripts/beanEthMigration.js"); +// ---- + const { upgradeWithNewFacets } = require("./scripts/diamond"); const { impersonateSigner, @@ -201,6 +206,11 @@ task("beanstalkAdmin", async function () { await mockBeanstalkAdmin(); }); +task("migrate-bip38", async function () { + await bipMigrateUnripeBean3CrvToBeanEth(); + await finishBeanEthMigration(); +}); + //////////////////////// SUBTASK CONFIGURATION //////////////////////// // Add a subtask that sets the action for the TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS task @@ -254,7 +264,7 @@ module.exports = { chainId: 5, url: process.env.GOERLI_RPC || "", timeout: 100000 - }, + } }, etherscan: { apiKey: process.env.ETHERSCAN_KEY From cca625052179764c930be707a68a43952ec54ddf Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 14:54:16 -0400 Subject: [PATCH 33/96] reset withdraw seasons in InitMigrateUnripeBean3CrvToBeanEth --- .../beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol index b4ebadd749..a3e0743dfa 100644 --- a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol +++ b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol @@ -27,5 +27,8 @@ contract InitMigrateUnripeBean3CrvToBeanEth { ); LibUnripe.decrementUnderlying(C.UNRIPE_LP, balanceOfUnderlying); LibUnripe.switchUnderlyingToken(C.UNRIPE_LP, C.BEAN_ETH_WELL); + + // Reset variable to 0 because it wasn't in BIP-36. + delete s.season.withdrawSeasons; } } \ No newline at end of file From 968f783d3d062b93f9f692accc9e7ad60d4f1ab6 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:09:18 -0400 Subject: [PATCH 34/96] update comments --- .../contracts/libraries/Oracle/LibEthUsdOracle.sol | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/protocol/contracts/libraries/Oracle/LibEthUsdOracle.sol b/protocol/contracts/libraries/Oracle/LibEthUsdOracle.sol index 1ffd3e3b21..5336fd4aaf 100644 --- a/protocol/contracts/libraries/Oracle/LibEthUsdOracle.sol +++ b/protocol/contracts/libraries/Oracle/LibEthUsdOracle.sol @@ -13,19 +13,19 @@ import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; * @title Eth Usd Oracle Library * @notice Contains functionalty to fetch a manipulation resistant ETH/USD price. * @dev - * The Oracle uses a greey approach to return the average price between the + * The Oracle uses a greedy approach to return the average price between the * current price returned ETH/USD Chainlink Oracle and either the ETH/USDC - * Uniswap V3 0.3 fee pool and the ETH/USDT Uniswap V3 0.3 fee pool depending + * Uniswap V3 0.05% fee pool and the ETH/USDT Uniswap V3 0.05% fee pool depending * on which is closer. - + * + * If the prices in the ETH/USDC Uniswap V3 0.05% fee pool and USD/USDT Uniswap V3 0.05% fee pool are + * greater than `MAX_DIFFERENCE` apart, then the oracle uses the Chainlink price to maximize liveness. + * * The approach is greedy as if the ETH/USDC Uniswap price is sufficiently close * to the Chainlink Oracle price (See {MAX_GREEDY_DIFFERENCE}), then the Oracle * will not check the ETH/USDT Uniswap Price to save gas. * - * There are several conditions that will cause the oracle to fail: - * 1. If the price in both Uniswap pools deviate from the Chainlink price - * by a sufficiently large percent (See {MAX_DIFFERENCE}). - * 2. If the Chainlink Oracle is broken or frozen (See: {LibChainlinkOracle}). + * The oracle will fail if the Chainlink Oracle is broken or frozen (See: {LibChainlinkOracle}). **/ library LibEthUsdOracle { From ba1d42bc9159881143c5f23ab03a7ba8078bd4b0 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:22:32 -0400 Subject: [PATCH 35/96] remove seeds reference from InitBipBasinIntegration --- .../beanstalk/init/InitBipBasinIntegration.sol | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol b/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol index b03ab87918..ef3bca005f 100644 --- a/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol +++ b/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol @@ -28,8 +28,8 @@ contract InitBipBasinIntegration { AppStorage internal s; - uint32 constant private NEW_BEAN_SEEDS_PER_BDV = 3e6; - uint32 constant private NEW_BEAN_3CRV_SEEDS_PER_BDV = 3.25e6; + uint32 constant private NEW_BEAN_GROWN_STALK_PER_BDV_PER_SEASON = 3e6; + uint32 constant private NEW_BEAN_3CRV_GROWN_STALK_PER_BDV_PER_SEASON = 3.25e6; uint32 constant private BEAN_ETH_SEEDS_PER_BDV = 4.5e6; uint32 constant private STALK_ISSUED_PER_BDV = 10000; @@ -38,8 +38,11 @@ contract InitBipBasinIntegration { function init() external { LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); - LibWhitelist.updateStalkPerBdvPerSeasonForToken(C.BEAN, NEW_BEAN_SEEDS_PER_BDV); - LibWhitelist.updateStalkPerBdvPerSeasonForToken(C.CURVE_BEAN_METAPOOL, NEW_BEAN_3CRV_SEEDS_PER_BDV); + LibWhitelist.updateStalkPerBdvPerSeasonForToken(C.BEAN, NEW_BEAN_GROWN_STALK_PER_BDV_PER_SEASON); + LibWhitelist.updateStalkPerBdvPerSeasonForToken( + C.CURVE_BEAN_METAPOOL, + NEW_BEAN_3CRV_GROWN_STALK_PER_BDV_PER_SEASON + ); LibWhitelist.whitelistToken( C.BEAN_ETH_WELL, IBDVFacet.wellBdv.selector, From c03f635ef655eb80a2f6a270c41f19bcbd4a66ad Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:23:21 -0400 Subject: [PATCH 36/96] update file name --- protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol b/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol index ef3bca005f..f24252b389 100644 --- a/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol +++ b/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol @@ -14,7 +14,7 @@ import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; /** * @author Publius - * @title InitBipWellsIntegration runs the code for the Basin Integration + * @title InitBipBasinIntegration runs the code for the Basin Integration **/ interface IBDVFacet { From 8aae31d683aeec50ccbc17985701b46223cc0a1d Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:25:44 -0400 Subject: [PATCH 37/96] remove unnecssary conditional --- protocol/contracts/ecosystem/price/WellPrice.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/protocol/contracts/ecosystem/price/WellPrice.sol b/protocol/contracts/ecosystem/price/WellPrice.sol index 9f923199b4..8ca79300e4 100644 --- a/protocol/contracts/ecosystem/price/WellPrice.sol +++ b/protocol/contracts/ecosystem/price/WellPrice.sol @@ -61,9 +61,6 @@ contract WellPrice { well.getSwapOut(wellTokens[beanIndex], wellTokens[tknIndex], 1e6) .mul(PRICE_PRECISION) .div(assetPrice); - } else { - // cannnot determine a price for bean if the other asset that bean is trading against is 0. - pool.price = 0; } // liquidity is calculated by getting the usd value of the bean portion of the pool, From ff742a6f5b0b166df988a2422e475d314b948fc9 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:28:12 -0400 Subject: [PATCH 38/96] add safe cast --- protocol/contracts/ecosystem/price/WellPrice.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/protocol/contracts/ecosystem/price/WellPrice.sol b/protocol/contracts/ecosystem/price/WellPrice.sol index 8ca79300e4..a263e37c0a 100644 --- a/protocol/contracts/ecosystem/price/WellPrice.sol +++ b/protocol/contracts/ecosystem/price/WellPrice.sol @@ -4,6 +4,7 @@ pragma experimental ABIEncoderV2; import {P} from "./P.sol"; import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol"; import {Call, IWell, IERC20} from "../../interfaces/basin/IWell.sol"; import {IBeanstalkWellFunction} from "../../interfaces/basin/IBeanstalkWellFunction.sol"; import {LibUsdOracle} from "../../libraries/Oracle/LibUsdOracle.sol"; @@ -24,6 +25,7 @@ interface dec{ contract WellPrice { using SafeMath for uint256; + using SafeCast for uint256; IBeanstalk private constant BEANSTALK = IBeanstalk(0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5); uint256 private constant WELL_DECIMALS = 1e18; @@ -91,7 +93,7 @@ contract WellPrice { wellFunction.data ); - deltaB = int256(beansAtPeg) - int256(reserves[beanIndex]); + deltaB = beansAtPeg.toInt256() - reserves[beanIndex].toInt256(); } } From 373c0948cce9730446111a943a4fd96dabd90025 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:29:57 -0400 Subject: [PATCH 39/96] fix natspec typo --- protocol/contracts/beanstalk/barn/FertilizerFacet.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index 2a7ab72161..ea10921669 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -105,7 +105,7 @@ contract FertilizerFacet { } /** - * @dev Returns the amount of Fertilize that can be purchased with `wethAmountIn` WETH. + * @dev Returns the amount of Fertilizer that can be purchased with `wethAmountIn` WETH. * Can be used to help calculate `minFertilizerOut` in `mintFertilizer`. * `wethAmountIn` has 18 decimals, `getEthUsdPrice()` has 6 decimals and `fertilizerAmountOut` has 0 decimals. */ From d27567c5f84bf07d604397f4d4549570ac9fb8c4 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:30:44 -0400 Subject: [PATCH 40/96] update natspec comment in _mow --- protocol/contracts/libraries/Silo/LibSilo.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/contracts/libraries/Silo/LibSilo.sol b/protocol/contracts/libraries/Silo/LibSilo.sol index 79c6046abf..e5629586b3 100644 --- a/protocol/contracts/libraries/Silo/LibSilo.sol +++ b/protocol/contracts/libraries/Silo/LibSilo.sol @@ -349,7 +349,7 @@ library LibSilo { AppStorage storage s = LibAppStorage.diamondStorage(); //sop stuff only needs to be updated once per season - //if it started raininga nd it's still raining, or there was a sop + //if it started raining and it's still raining, or there was a sop if (s.season.rainStart > s.season.stemStartSeason) { uint32 lastUpdate = _lastUpdate(account); if (lastUpdate <= s.season.rainStart && lastUpdate <= s.season.current) { From 81e452e41c2533dfc49543dc70fba15ed3c6cc2f Mon Sep 17 00:00:00 2001 From: Brean0 Date: Mon, 25 Sep 2023 17:04:41 +0900 Subject: [PATCH 41/96] update sciNotation comment --- protocol/contracts/beanstalk/metadata/MetadataImage.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/contracts/beanstalk/metadata/MetadataImage.sol b/protocol/contracts/beanstalk/metadata/MetadataImage.sol index 8e7989c67f..459c70bd76 100644 --- a/protocol/contracts/beanstalk/metadata/MetadataImage.sol +++ b/protocol/contracts/beanstalk/metadata/MetadataImage.sol @@ -533,14 +533,14 @@ contract MetadataImage { function sciNotation(int96 stem) internal pure returns (string memory) { if (stem >= 0) { - // if stem is greater than 1e7, use scientific notation + // if stem is greater than 1e5, use scientific notation if (stem > 100_000) { return powerOfTen(uint256(stem)); } else { return uint256(stem).toString(); } } else { - // if stem is greater than 1e7, use scientific notation + // if stem is less than -1e5, use scientific notation if (-stem > 100_000) { return string(abi.encodePacked("-", powerOfTen(uint256(-stem)))); } else { From e155521bb51d21328184ca6a125d0ee4346bdbd8 Mon Sep 17 00:00:00 2001 From: Brean0 Date: Mon, 25 Sep 2023 18:57:11 +0900 Subject: [PATCH 42/96] added proper testnet mocks for quicker metadata testing. - additionally, changed generate image from `view` to `pure`. --- .../beanstalk/metadata/MetadataImage.sol | 2 +- .../contracts/mocks/MockMetadataERC1155.sol | 51 +++++++++++ .../contracts/mocks/MockMetadataFacet.sol | 85 +++++++++++++++++++ protocol/hardhat.config.js | 1 + protocol/scripts/deployMockMetadata.js | 25 ++++++ 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 protocol/contracts/mocks/MockMetadataERC1155.sol create mode 100644 protocol/contracts/mocks/MockMetadataFacet.sol create mode 100644 protocol/scripts/deployMockMetadata.js diff --git a/protocol/contracts/beanstalk/metadata/MetadataImage.sol b/protocol/contracts/beanstalk/metadata/MetadataImage.sol index 459c70bd76..b22edf6a2a 100644 --- a/protocol/contracts/beanstalk/metadata/MetadataImage.sol +++ b/protocol/contracts/beanstalk/metadata/MetadataImage.sol @@ -36,7 +36,7 @@ contract MetadataImage { ); } - function generateImage(address token, int96 stem, int96 stemTip) internal view returns (string memory) { + function generateImage(address token, int96 stem, int96 stemTip) internal pure returns (string memory) { int96 grownStalkPerBdv = stemTip - stem; return string( abi.encodePacked( diff --git a/protocol/contracts/mocks/MockMetadataERC1155.sol b/protocol/contracts/mocks/MockMetadataERC1155.sol new file mode 100644 index 0000000000..ffbb3e08e7 --- /dev/null +++ b/protocol/contracts/mocks/MockMetadataERC1155.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.7.6; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; + +/** + * @author brean + * @dev used to deploy on testnets to verify that json data and SVG encoding is correct. + * Steps for testing: + * 1: deploy MockMetadataFacet + * 2: deploy MetadataMockERC1155 with the address of the MockMetadataFacet. + * (MockMetadataFacet with ERC1155 exceeds the contract size limit.) +**/ + +interface IMetadataFacet { + function uri(uint256 depositId) external view returns (string memory); + + function name() external pure returns (string memory); + + function symbol() external pure returns (string memory); +} + +contract MockMetadataERC1155 is ERC1155 { + + address public mockMetadataFacetaddress; + + constructor (string memory name, address metadataAddress) ERC1155(name) { + mockMetadataFacetaddress = metadataAddress; + } + + function mockMint(address account, uint256 id, uint256 amount) external { + _mint(account, id, amount, new bytes(0)); + } + + function changeMetadataFacet(address metadataAddress) external { + mockMetadataFacetaddress = metadataAddress; + } + + function uri(uint256 depositId) external override view returns (string memory) { + return IMetadataFacet(mockMetadataFacetaddress).uri(depositId); + } + + function name() external view returns (string memory){ + return IMetadataFacet(mockMetadataFacetaddress).name(); + } + + function symbol() external view returns (string memory){ + return IMetadataFacet(mockMetadataFacetaddress).symbol(); + } +} \ No newline at end of file diff --git a/protocol/contracts/mocks/MockMetadataFacet.sol b/protocol/contracts/mocks/MockMetadataFacet.sol new file mode 100644 index 0000000000..b58b1f3f5f --- /dev/null +++ b/protocol/contracts/mocks/MockMetadataFacet.sol @@ -0,0 +1,85 @@ +/* + SPDX-License-Identifier: MIT +*/ + +pragma solidity =0.7.6; +pragma experimental ABIEncoderV2; + +import "contracts/beanstalk/metadata/MetadataImage.sol"; +import {LibBytes} from "contracts/libraries/LibBytes.sol"; +import {LibTokenSilo} from "contracts/libraries/Silo/LibTokenSilo.sol"; +import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; + +/** + * @author brean + * @title MockMetadataFacet is a Mock version of MetadataFacet. + * @dev used to deploy on testnets to verify that json data and SVG encoding is correct. + * Steps for testing: + * 1: deploy MockMetadataFacet + * 2: deploy MetadataMockERC1155 with the address of the MockMetadataFacet. + * (MockMetadataFacet with ERC1155 exceeds the contract size limit.) +**/ +contract MockMetadataFacet is MetadataImage { + using SafeMath for uint256; + + // inital conditions: 2 seeds, 1000 seasons has elapsed from milestone season. + uint256 public stalkEarnedPerSeason = 2e6; + uint256 public seasonsElapsed = 1000; + uint256 public stalkIssuedPerBdv = 10000; + + using LibStrings for uint256; + using LibStrings for int256; + + event URI(string _uri, uint256 indexed _id); + + /** + * @notice Returns the URI for a given depositId. + * @param depositId - the id of the deposit + * @dev the URI is a base64 encoded JSON object that contains the metadata and base64 encoded svg. + * Deposits are stored as a mapping of a uint256 to a Deposit struct. + * ERC20 deposits are represented by the concatination of the token address and the stem. (20 + 12 bytes). + */ + function uri(uint256 depositId) external view returns (string memory) { + (address token, int96 stem) = LibBytes.unpackAddressAndStem(depositId); + int96 stemTip = int96(stalkEarnedPerSeason.mul(seasonsElapsed)); + bytes memory attributes = abi.encodePacked( + '\\n\\nToken Symbol: ', getTokenName(token), + '\\nToken Address: ', LibStrings.toHexString(uint256(token), 20), + '\\nId: ', depositId.toHexString(32), + '\\nstem: ', int256(stem).toString(), + '\\ninital stalk per BDV: ', stalkIssuedPerBdv.toString(), + '\\ngrown stalk per BDV: ', uint256(stemTip - stem).toString(), + '\\nstalk grown per BDV per season: ', stalkEarnedPerSeason.toString(), + '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."' + ); + return string(abi.encodePacked("data:application/json;base64,",LibBytes64.encode(abi.encodePacked( + '{', + '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage.', + attributes, + string(abi.encodePacked(', "image": "', imageURI(token, stem, stemTip), '"')), + '}' + )) + )); + } + + function name() external pure returns (string memory){ + return "Beanstalk Silo Deposits"; + } + + function symbol() external pure returns (string memory){ + return "DEPOSIT"; + } + + function setSeeds(uint256 _stalkEarnedPerSeason) external { + stalkEarnedPerSeason = _stalkEarnedPerSeason; + } + + function setSeasonElapsed(uint256 _seasonsElapsed) external { + seasonsElapsed = _seasonsElapsed; + } + + function setStalkIssuedPerBdv(uint256 _stalkIssuedPerBdv) external { + stalkIssuedPerBdv = _stalkIssuedPerBdv; + } + +} diff --git a/protocol/hardhat.config.js b/protocol/hardhat.config.js index 7513790a17..8e4daa15df 100644 --- a/protocol/hardhat.config.js +++ b/protocol/hardhat.config.js @@ -253,6 +253,7 @@ module.exports = { goerli: { chainId: 5, url: process.env.GOERLI_RPC || "", + accounts: [process.env.GOERLI_PRIVATE_KEY], timeout: 100000 }, }, diff --git a/protocol/scripts/deployMockMetadata.js b/protocol/scripts/deployMockMetadata.js new file mode 100644 index 0000000000..f07030360c --- /dev/null +++ b/protocol/scripts/deployMockMetadata.js @@ -0,0 +1,25 @@ +const hre = require("hardhat"); + + +async function main() { + const MockMetadataFacet = await ethers.getContractFactory('MockMetadataFacet'); + console.log('Deploying MockMetadataFacet...'); + const mockMetadataFacet = await MockMetadataFacet.deploy(); + await mockMetadataFacet.deployed(); + console.log('mockMetadataFacet deployed to:', mockMetadataFacet.address); + + // only needs to be deployed once. Deploy a new mockMetdata facet, then change the address on MockMetadataERC1155. + const MockMetadataERC1155 = await ethers.getContractFactory('MockMetadataERC1155'); + console.log('Deploying MockMetadataERC1155...'); + const mockMetadataERC1155 = await MockMetadataERC1155.deploy('TEST', '0xE40036Db7c1E5f366153B16a2c249EB2bf04bCcc'); + await mockMetadataERC1155.deployed(); + console.log('metadataMockERC1155 deployed to:', mockMetadataERC1155.address); + + } + + main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); \ No newline at end of file From 4489cb869b1a1f8a2535a04364460c79ffb75b11 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 25 Sep 2023 13:17:17 -0400 Subject: [PATCH 43/96] require > 0 fertilizer bought in mintFertilizer --- protocol/contracts/beanstalk/barn/FertilizerFacet.sol | 3 ++- protocol/test/Fertilizer.test.js | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index ea10921669..75c02783f9 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -78,7 +78,8 @@ contract FertilizerFacet { fertilizerAmountOut = getMintFertilizerOut(wethAmountIn); - require(fertilizerAmountOut >= minFertilizerOut, "Fertilizer Not enough bought."); + require(fertilizerAmountOut >= minFertilizerOut, "Fertilizer: Not enough bought."); + require(fertilizerAmountOut > 0, "Fertilizer: None bought."); uint128 remaining = uint128(LibFertilizer.remainingRecapitalization().div(1e6)); // remaining <= 77_000_000 so downcasting is safe. require(fertilizerAmountOut <= remaining, "Fertilizer: Not enough remaining."); diff --git a/protocol/test/Fertilizer.test.js b/protocol/test/Fertilizer.test.js index a7a1df7540..d3ca109422 100644 --- a/protocol/test/Fertilizer.test.js +++ b/protocol/test/Fertilizer.test.js @@ -270,6 +270,11 @@ describe('Fertilize', function () { }) describe("Mint Fertilizer", async function () { + it('Reverts if mints 0', async function () { + await this.season.teleportSunrise('6274') + await expect(this.fertilizer.connect(user).mintFertilizer('0', '0', '0', EXTERNAL)).to.be.revertedWith('Fertilizer: None bought.') + }) + describe('1 mint', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') From 47fef03a37527c839acd4696db08fbf0bbcd5a71 Mon Sep 17 00:00:00 2001 From: Brean0 Date: Tue, 26 Sep 2023 16:03:50 +0900 Subject: [PATCH 44/96] update metadata to put values in traits rather than in description. - this allows users of NFT marketplaces to filter NFTs by criteria's. --- .../beanstalk/metadata/MetadataFacet.sol | 18 ++++++++--------- .../contracts/mocks/MockMetadataFacet.sol | 20 +++++++++---------- protocol/scripts/deployMockMetadata.js | 2 +- protocol/test/data/base64EncodedImageBean.txt | 2 +- .../test/data/base64EncodedImageBean3Crv.txt | 2 +- .../test/data/base64EncodedImageBeanEth.txt | 2 +- .../test/data/base64EncodedImageUrBean.txt | 2 +- .../test/data/base64EncodedImageUrBeanEth.txt | 2 +- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/protocol/contracts/beanstalk/metadata/MetadataFacet.sol b/protocol/contracts/beanstalk/metadata/MetadataFacet.sol index 16290a63ba..b4df7233c1 100644 --- a/protocol/contracts/beanstalk/metadata/MetadataFacet.sol +++ b/protocol/contracts/beanstalk/metadata/MetadataFacet.sol @@ -36,18 +36,18 @@ contract MetadataFacet is MetadataImage { int96 stemTip = LibTokenSilo.stemTipForToken(token); require(token != address(0), "Silo: metadata does not exist"); bytes memory attributes = abi.encodePacked( - '\\n\\nToken Symbol: ', getTokenName(token), - '\\nToken Address: ', LibStrings.toHexString(uint256(token), 20), - '\\nId: ', depositId.toHexString(32), - '\\nstem: ', int256(stem).toString(), - '\\ninital stalk per BDV: ', uint256(LibTokenSilo.stalkIssuedPerBdv(token)).toString(), - '\\ngrown stalk per BDV: ', uint256(stemTip - stem).toString(), - '\\nstalk grown per BDV per season: ', uint256(LibTokenSilo.stalkEarnedPerSeason(token)).toString(), - '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."' + ', "attributes": [ { "trait_type": "Token", "value": "', getTokenName(token), + '"}, { "trait_type": "Token Address", "value": "', LibStrings.toHexString(uint256(token), 20), + '"}, { "trait_type": "Id", "value": "', depositId.toHexString(32), + '"}, { "trait_type": "stem", "display_type": "number", "value": ', int256(stem).toString(), + '}, { "trait_type": "inital stalk per BDV", "display_type": "number", "value": ', uint256(LibTokenSilo.stalkIssuedPerBdv(token)).toString(), + '}, { "trait_type": "grown stalk per BDV", "display_type": "number", "value": ', uint256(stemTip - stem).toString(), + '}, { "trait_type": "stalk grown per BDV per season", "display_type": "number", "value": ', uint256(LibTokenSilo.stalkEarnedPerSeason(token)).toString() ); return string(abi.encodePacked("data:application/json;base64,",LibBytes64.encode(abi.encodePacked( '{', - '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage.', + '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage. ', + '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."', attributes, string(abi.encodePacked(', "image": "', imageURI(token, stem, stemTip), '"')), '}' diff --git a/protocol/contracts/mocks/MockMetadataFacet.sol b/protocol/contracts/mocks/MockMetadataFacet.sol index b58b1f3f5f..ad6cc38b1e 100644 --- a/protocol/contracts/mocks/MockMetadataFacet.sol +++ b/protocol/contracts/mocks/MockMetadataFacet.sol @@ -43,20 +43,20 @@ contract MockMetadataFacet is MetadataImage { (address token, int96 stem) = LibBytes.unpackAddressAndStem(depositId); int96 stemTip = int96(stalkEarnedPerSeason.mul(seasonsElapsed)); bytes memory attributes = abi.encodePacked( - '\\n\\nToken Symbol: ', getTokenName(token), - '\\nToken Address: ', LibStrings.toHexString(uint256(token), 20), - '\\nId: ', depositId.toHexString(32), - '\\nstem: ', int256(stem).toString(), - '\\ninital stalk per BDV: ', stalkIssuedPerBdv.toString(), - '\\ngrown stalk per BDV: ', uint256(stemTip - stem).toString(), - '\\nstalk grown per BDV per season: ', stalkEarnedPerSeason.toString(), - '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."' + ', "attributes": [ { "trait_type": "Token", "value": "', getTokenName(token), + '"}, { "trait_type": "Token Address", "value": "', LibStrings.toHexString(uint256(token), 20), + '"}, { "trait_type": "Id", "value": "', depositId.toHexString(32), + '"}, { "trait_type": "stem", "display_type": "number", "value": ', int256(stem).toString(), + '}, { "trait_type": "inital stalk per BDV", "display_type": "number", "value": ', stalkIssuedPerBdv.toString(), + '}, { "trait_type": "grown stalk per BDV", "display_type": "number", "value": ', uint256(stemTip - stem).toString(), + '}, { "trait_type": "stalk grown per BDV per season", "display_type": "number", "value": ', stalkEarnedPerSeason.toString() ); return string(abi.encodePacked("data:application/json;base64,",LibBytes64.encode(abi.encodePacked( '{', - '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage.', + '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage. ', + '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."', attributes, - string(abi.encodePacked(', "image": "', imageURI(token, stem, stemTip), '"')), + string(abi.encodePacked('}], "image": "', imageURI(token, stem, stemTip), '"')), '}' )) )); diff --git a/protocol/scripts/deployMockMetadata.js b/protocol/scripts/deployMockMetadata.js index f07030360c..5d8845977f 100644 --- a/protocol/scripts/deployMockMetadata.js +++ b/protocol/scripts/deployMockMetadata.js @@ -11,7 +11,7 @@ async function main() { // only needs to be deployed once. Deploy a new mockMetdata facet, then change the address on MockMetadataERC1155. const MockMetadataERC1155 = await ethers.getContractFactory('MockMetadataERC1155'); console.log('Deploying MockMetadataERC1155...'); - const mockMetadataERC1155 = await MockMetadataERC1155.deploy('TEST', '0xE40036Db7c1E5f366153B16a2c249EB2bf04bCcc'); + const mockMetadataERC1155 = await MockMetadataERC1155.deploy('TEST', '0x12a5c6fdF938F276bdf67961a9cc0B58092eDAC9'); await mockMetadataERC1155.deployed(); console.log('metadataMockERC1155 deployed to:', mockMetadataERC1155.address); diff --git a/protocol/test/data/base64EncodedImageBean.txt b/protocol/test/data/base64EncodedImageBean.txt index 4ff6e6acf8..bb4bdcdbdb 100644 --- a/protocol/test/data/base64EncodedImageBean.txt +++ b/protocol/test/data/base64EncodedImageBean.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IEJFQU5cblRva2VuIEFkZHJlc3M6IDB4YmVhMDAwMDAyOWFkMWM3N2QzZDVkMjNiYTJkODg5M2RiOWQxZWZhYlxuSWQ6IDB4YmVhMDAwMDAyOWFkMWM3N2QzZDVkMjNiYTJkODg5M2RiOWQxZWZhYjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMlxuc3RlbTogMlxuaW5pdGFsIHN0YWxrIHBlciBCRFY6IDEwMDAwXG5ncm93biBzdGFsayBwZXIgQkRWOiAyMDAwXG5zdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb246IDIwMDAwMDBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCamJHRnpjejBpYzNablFtOWtlU0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJek5UQWlJSFpwWlhkQ2IzZzlJakFnTUNBeU5UVWdNelV3SWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhodGJHNXpPbmhzYVc1clBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJajQ4WkdWbWN6NDhaeUJwWkQwaWNHeHZkQ0krUEhCaGRHZ2daRDBpVFRjNUxqVTNNamdnTVRJNUxqSTJOVXd4TWpjdU5EWTVJREUxTmk0NE16Tk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UQXhMalk1TjB3M09TNDFOekk0SURFeU9TNHlOalZhSWlCbWFXeHNQU0lqT1RRMFFUSTNJaTgrUEhCaGRHZ2daRDBpVFRjNUxqVXpNeklnTVRNekxqUXlOa3czT1M0MU56STNJREV5T1M0eU5qVk1NVEkzTGpRMk9TQXhOVFl1T0RNelRERXlOeTQxTURjZ01UWXdMamt3T0V3M09TNDFNek15SURFek15NDBNalphSWlCbWFXeHNQU0lqTnpVek9URkdJaTgrUEhCaGRHZ2daRDBpVFRFM05TNDBOamNnTVRNekxqUk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UVTJMamd6TTB3eE1qY3VOVEEzSURFMk1DNDVNRGhNTVRjMUxqUTJOeUF4TXpNdU5Gb2lJR1pwYkd3OUlpTTJOek16TVVVaUx6NDhMMmMrUEdjZ2FXUTlJbVoxYkd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUWXdJaUI1UFNJeE5DSWdabWxzYkQwaUkwRTRRemd6UVNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUY3pJaUI1UFNJeU1TSWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKbGJYQjBlVkJzYjNRaVBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQnNiM1FpSUhnOUlpMHpOU0lnZVQwaU1DSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSndZWEowYVdGc1RHVmhabEp2ZHlJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaU1DSWdlVDBpTUNJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1lpSUhnOUlpMHhNaUlnZVQwaUxUY2lMejQ4TDJjK1BHY2dhV1E5SW5CaGNuUnBZV3hNWldGbVVHeHZkQ0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0d4dmRDSWdlRDBpTFRNMUlpQjVQU0l3SWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5zWldGbVVtOTNJaUI0UFNJdE16VWlJSGs5SWpBaUlHWnBiR3c5SWlOQk9FTTRNMEVpSUhSeVlXNXpabTl5YlQwaWMyTmhiR1VvTVM0MEtTSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdaU2IzY2lJSGc5SWkwME55SWdlVDBpTnlJZ1ptbHNiRDBpSXpnNVFUWXlSaUlnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR0Z5ZEdsaGJFeGxZV1pTYjNjaUlIZzlJaTAyTUNJZ2VUMGlNVFFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmlJK1BIQmhkR2dnWkQwaVRURTNNUzQ0T0RRZ01URTRMams0TTJFMExqa3pNaUEwTGprek1pQXdJREFnTVMweExqQXhPQ0F5TGpZd05pQTBMamN4TlNBMExqY3hOU0F3SURBZ01TMHhMamczT0NBeExqUXpPV010TGpRMk5TNHhPVFV0TVM0M016VXVOekkzTFRJdU16WTBMakUzTmkwdU1qUTJJRE11TWprNExURXVOVGt6SURZdU5URXlMVEl1TWpVeklEY3VPVFUwWVRRdU5UTXlJRFF1TlRNeUlEQWdNQ0F4TFM0ek1UTXRMamt6TTJNdExqSXhNUzB1T1RjMUxTNHdNemd0TVM0M05qTXVNRGM0TFRJdU1qazFMakl3TWkwdU9USXhMak0xTXkweExqWXhNaTQwTmpjdE1pNHhOQzB4TGpFM055NDJPVFF0TWk0Mk5ESXVOVFk1TFRNdU5UVTRMUzR5TnpJdExqYzVOaTB1TnpNeUxURXVNRGd6TFRFdU9USXhMUzQzTkRNdE15NHdNelF1TkRrNExqQXhNU0F4TGprek9TNHhNRGtnTXk0eU5EY2dNUzR4TmpkaE5TNHhNeUExTGpFeklEQWdNQ0F4SURFdU1qRWdNUzQwTVROakxqRTFPUzB1TnpRdU1UazVMUzQ1TlRndU1qTTRMVEV1TVRjNUxqSXdPUzB4TGpJeE15NHpNakl0TVM0NE56SXVNamMwTFRJdU56STBZVGN1TnpNZ055NDNNeUF3SURBZ01DMHVPVEE0TFRNdU1UYzNZeTB1TnpjeUxqUXhOUzB4TGpjNE9TNHhPVFl0TWk0ek56Z3RMak13TkMwdU16TTVMUzR5T0RjdExqVTFOaTB1TmpneUxTNDNOalF0TVM0Mk9USmhNVEl1TnpNNUlERXlMamN6T1NBd0lEQWdNUzB1TVRjMkxUTXVPVEE1WXk0M09Ea3VOakF6SURFdU5EY2dNUzR3TVRrZ01TNDVNemNnTVM0eU9ETXVPVFEwTGpVek5pQXhMak0wTkM0Mk16a2dNUzQzTmpFZ01TNHhOamN1TVRVeUxqRTVNeTQyTkRrdU9EUXlMalU0TmlBeExqYzFNUzB1TURFeExqRTNNaTB1TURVekxqYzVOUzB1TkRZMElERXVNamt6WVRZdU9ETWdOaTQ0TXlBd0lEQWdNU0F4TGpNNE5DQXlMakl5TjJNdU1UUXVNelk0TGpJME1pNDNORFF1TXpFeElERXVNVFV1TVRBM0xTNHlNRGN1TWpZeExTNDBNemt1TlRFeExTNDNNakl1TkRVekxTNDFNVE11T0RjdExqazVNaUF4TGpZd05DMHhMakk0TkM0Mk9ETXRMakkzTWlBeExqSTRMUzR5TkRrZ01TNDNNak10TGpJek5HRTFMak13TWlBMUxqTXdNaUF3SURBZ01TQXhMalE0Tmk0eU56TmFJaTgrUEM5blBqeG5JR2xrUFNKemFXeHZJajQ4Y0dGMGFDQmtQU0pOTlRjdU1UQTRJRGN4TGpJNVl5NHhPRGd0TVRFdU5qVXpMVEV5TGpBeExUSXhMak13TXkweU55NHlORE10TWpFdU5UVXlMVEUxTGpJek5DMHVNalV0TWpjdU56TTJJRGd1T1RrMUxUSTNMamt5TXlBeU1DNDJORGt0TGpFNE55QXhNUzQyTlRRZ01USXVNREVnTWpFdU16QTBJREkzTGpJME5DQXlNUzQxTlRNZ01UVXVNak16TGpJMUlESTNMamN6TlMwNExqazVOU0F5Tnk0NU1qSXRNakF1TmpWYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFM0ME5qUWdNVGt1TlRRMFl5NDJPVGtnTVRZdU5UZzFJREV1TkNBek15NHhOamtnTWk0d09UZ2dORGt1TnpVeUxqQXlNU0F5TGpNNE1TNDBPQ0EwTGpJM09DNDRPRE1nTlM0MU16a3VNamMzTGpnMkxqYzBNU0F5TGpJM05TQXhMamMzT0NBekxqZzJOeTQwT1RRdU56VTVJREV1TWpFeUlERXVOeUF6TGpBd01pQXpMak16TWlBeExqY3pPU0F4TGpVNE5pQXpMak0xSURNdU1EVTJJRFV1TnpNeUlEUXVNems0SURNdU1qa3pJREV1T0RVMUlEWXVNVFV4SURJdU16azJJRGd1TnpreElESXVPRGsySURFdU9EVTFMak0xSURVdU1UUTVMamswT0NBNUxqUTRPQzQxTlRaaE16SXVOekEzSURNeUxqY3dOeUF3SURBZ01DQTVMak14TlMweUxqSTROMk14TGpnMk1pMHVOelU1SURRdU5qUXlMVEV1T1RFM0lEY3VOak16TFRRdU5DQXhMak0wT0MweExqRXlJRE11TkRRNExUSXVPRGszSURVdU1UazNMVFV1T1RWaE1qQXVNVEUwSURJd0xqRXhOQ0F3SURBZ01DQXlMakkxTFRVdU9UazRZeTR5TVMweE55NDFOVEl1TkRJdE16VXVNVEEwTGpZek1pMDFNaTQyTlRkc0xUVTJMamd1T1RVeWFDNHdNREZhSWlCbWFXeHNQU0lqUWpOQ00wSXpJaTgrUEhCaGRHZ2daRDBpVFRVM0xqUTRJREU1TGpRNE1rTTFOeTQyTkRVZ09TNHlOQ0EwTkM0NU56Z3VOekkzSURJNUxqRTROeTQwTmpnZ01UTXVNemszTGpJeExqUTJNeUE0TGpNd015NHlPVGdnTVRndU5UUTJMakV6TkNBeU9DNDNPRGdnTVRJdU9DQXpOeTR6SURJNExqVTVNU0F6Tnk0MU5tTXhOUzQzT1M0eU5UZ2dNamd1TnpJMExUY3VPRE0xSURJNExqZzRPUzB4T0M0d056aGFJaUJtYVd4c1BTSWpRME5ESWk4K1BIQmhkR2dnWkQwaVRUTXdMak14TkNBM0xqRXpOMk11TURBNUxTNDFOakV0TGpZNExURXVNREk0TFRFdU5UTTRMVEV1TURReUxTNDROVGt0TGpBeE5DMHhMalUyTWk0ME15MHhMalUzTVM0NU9URXRMakF4TGpVMk1pNDJPQ0F4TGpBeU9DQXhMalV6T0NBeExqQTBNaTQ0TlRrdU1ERTFJREV1TlRZeUxTNDBNeUF4TGpVM0xTNDVPVm9pSUdacGJHdzlJaU0yTmpZaUx6NDhjR0YwYUNCa1BTSk5OaTQwTVRRZ01qZ3VPRGxoTVRVdU56YzNJREUxTGpjM055QXdJREFnTVMweUxqQTVNeTB5TGpFME5tTXRMamcxTmkweExqQTJNeTB5TGpRMU15MHpMakE1TXkweUxqazNOUzAyTGpFeE1tRXhNUzQzTmpVZ01URXVOelkxSURBZ01DQXhMUzR3T1RNdE15NHpNRGRzTWpVdU5ETXRPUzQ1TnpaakxqQTBNeTR4TkRJdU1UZzRMalUxTlM0Mk1EUXVPRFk0TGpRMkxqTTBOaTQ1TkRjdU16UWdNUzR3T0RZdU16TTBURFl1TkRFeklESTRMamc0T0hZdU1EQXlXaUlnWm1sc2JEMGlJMFUyUlRaRk5pSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNHpNeUlnWkQwaVRURXVORGMzSURFMkxqQXlPV011TWpVdExqa3pNUzQzTURZdE1pNHlOVGdnTVM0MU55MHpMalk1TlM0Mk5UVXRNUzR3T1RJZ01TNHlPVEl0TVM0NE1qVWdNUzQzTmkweUxqTTFPQzQxT0RRdExqWTJOU0F4TGpjM05pMHhMamt6TkNBekxqWTNPUzB6TGpJNUlESXVPVFV6TFRJdU1UQTFJRFV1TmprMkxUTXVNRFVnTnk0M01qTXRNeTQzTTJFek55NHpOU0F6Tnk0ek5TQXdJREFnTVNBMkxqUTROUzB4TGpVME4ydzFMakkwTWlBMExqTXhObUV4TGpRNElERXVORGdnTUNBd0lEQXRNUzR5TVRRdU9UWTNUREV1TkRnZ01UWXVNRE5vTFM0d01ESmFJaUJtYVd4c1BTSWpPVGs1SWk4K1BIQmhkR2dnYjNCaFkybDBlVDBpTGpRMElpQmtQU0pOTVM0NE1TQXlOaTQxTXpKakxqSXdOaTQwT1RRdU5EZzBJREV1TURVdU9EWWdNUzQyTTJFeE1DNHlOallnTVRBdU1qWTJJREFnTUNBd0lESXVNamM0SURJdU5EZzJURFl1TlRVeUlEYzRMakl5WVRFM0xqSTNNaUF4Tnk0eU56SWdNQ0F3SURFdE15MDNMalF4TTB3eExqZ3hJREkyTGpVek1sb2lJR1pwYkd3OUlpTkZOa1UyUlRZaUx6NDhjR0YwYUNCa1BTSnRNek11TURreUlEUTVMalEwTVMwMkxqTTRNU0F4TlM0eU1URnpMVFl1TURjNExURXhMakUxT1NBMkxqTTRNUzB4TlM0eU1Wb2lJR1pwYkd3OUlpTTRSVGhGT0VVaUx6NDhjR0YwYUNCa1BTSnRNall1TnpJMUlEWTBMamcxT0MwdU1Ea3hMUzR4TnpWakxTNHdNall0TGpBME9TMHlMall6TkMwMExqa3lNeTB1T0RZM0xUa3VNemNnTVM0d05UY3RNaTQzTVRjZ015NDFNVGd0TkM0M01qVWdOeTR6TFRVdU9UUTJiQzR4T0RjdExqQTJNUzAyTGpVeklERTFMalUxTWxwdE5pNHlNVEl0TVRVdU1qWTRZeTB6TGpZeU1TQXhMakl4TnkwMUxqazVNU0F6TGpFMk9DMDNMakF5TWlBMUxqYzVPQzB4TGpVek9DQXpMamt3T0M0ek5UVWdPQzR4TmpZdU56ZzRJRGt1TURVMGJEWXVNak0wTFRFMExqZzFNbHBOTWpndU1Ea3pJRFl6TGpjek4ydzBMalE0TkMweE1DNDROM00zTGpNMk5TQTJMak16TnkwMExqUTROQ0F4TUM0NE4xb2lJR1pwYkd3OUlpTTRSVGhGT0VVaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNME5rSTVOVFVpTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGpORFVsWWlQanh5WldOMElIazlJaTQxSWlCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU56WTBMVE11TlRBMElEa3VNelpUTGpJNU9DQTBMalE1T1NBM0xqWTROeUF4TGpjMk5Wb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNHhNeklnT0M0d056aGpMUzQwTmpZdU5qUXRNUzR5T1RjZ01TNHpNak10TWk0Mk9UVWdNUzQ1T1RKc01pNHhNall0TlM0M056ZGpMakE0T1M0d09TNHhPVE11TWpBMExqTXVNek00TGpNd015NHpOelV1TmpJMUxqZzVNUzQzTkRRZ01TNDBPRFF1TVRFM0xqVTRNeTR3TkNBeExqSTFNeTB1TkRjMUlERXVPVFl6V2lJZ1ptbHNiRDBpZFhKc0tDTmhLU0lnYzNSeWIydGxQU0lqWm1abUlpQnpkSEp2YTJVdGQybGtkR2c5SWk0MUlpOCtQR1JsWm5NK1BHeHBibVZoY2tkeVlXUnBaVzUwSUdsa1BTSmhJaUI0TVQwaU5pNDVOU0lnZVRFOUlqTXVPRFV6SWlCNE1qMGlOaTQ1TlNJZ2VUSTlJakV3TGpVME5DSWdaM0poWkdsbGJuUlZibWwwY3owaWRYTmxjbE53WVdObFQyNVZjMlVpUGp4emRHOXdJSE4wYjNBdFkyOXNiM0k5SWlNNE1qQXlNRElpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJaTR4T0RJaUlITjBiM0F0WTI5c2IzSTlJaU5HTnpGRk1EVWlMejQ4YzNSdmNDQnZabVp6WlhROUlpNDFNVFlpSUhOMGIzQXRZMjlzYjNJOUlpTkdNRVkxTURjaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWk0M016UWlJSE4wYjNBdFkyOXNiM0k5SWlNNE5VTkVOelVpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJakVpSUhOMGIzQXRZMjlzYjNJOUlpTXdNamxFUmtJaUx6NDhMMnhwYm1WaGNrZHlZV1JwWlc1MFBqd3ZaR1ZtY3o0OEwyYytQR2NnYVdROUluVnlRa1ZCVGlJK1BISmxZM1FnZDJsa2RHZzlJakV5SWlCb1pXbG5hSFE5SWpFeUlpQnllRDBpTmlJZ1ptbHNiRDBpSXpkR05UVXpNeUl2UGp4d1lYUm9JR1E5SW0wM0xqWTROeUF4TGpJMk5TMHpMalV3TkNBNUxqTTJVeTR5T1RnZ015NDVPVGtnTnk0Mk9EY2dNUzR5TmpaYWJTMHlMalk1TVNBNExqYzRJREl1TkRZeUxUWXVOamt4Y3pRdU5UTTRJRE11TmpjdE1pNDBOaklnTmk0Mk9URmFJaUJtYVd4c1BTSWpabVptSWk4K1BDOW5QanhuSUdsa1BTSkNSVUZPUlZSSUlqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamcwSURFdU1qWTFMVE11TlRBMUlEa3VNelpqTGpBd015QXdMVE11T0RnMExUWXVOakkxSURNdU5UQTFMVGt1TXpaYUlpQm1hV3hzUFNJalptWm1JaTgrUEhCaGRHZ2daRDBpVFRndU9UVXlJRFl1T1RnMllTNHdOak11TURZeklEQWdNQ0F4TFM0d01qSXVNREF6WXkwdU56RXVNVE10TVM0ME1qUXVNalUxTFRJdU1UTTBMak00TVMwdU1qZ3hMakExTWkwdU5UWTFMakV3TXkwdU9EUTJMakUxTW1FdU1ETTJMakF6TmlBd0lEQWdNUzB1TURJMklEQnNNaTR4TkMwMUxqWXlOUzR3TURRdExqQXdNMk11TWprM0lERXVOekF5TGpVNUlETXVNemswTGpnNE5DQTFMakE1TWxwdExTNHhPRGN1TkRjNFl5MHhMakkyTmk0NE5Ua3RNaTQxTXpFZ01TNDNNakV0TXk0NElESXVOVGhzTGpjNE1TMHlMakExTkdNdU1EQTNMakF3TkM0d01UTWdNQ0F1TURJeklEQWdMamMxT1MwdU1UTXlJREV1TlRFMExTNHlOamdnTWk0eU55MHVOR3d1TmprM0xTNHhNall1TURNdExqQXdObU10TGpBd05DNHdNRE1nTUNBdU1EQTJJREFnTGpBd05sb2lJR1pwYkd3OUlpTXdNREFpTHo0OEwyYytQR2NnYVdROUluVnlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6ZEdOVFV6TXlJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSnNaV0ZtVW05M0lqNDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXdJaUI1UFNJd0lpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlMVEV5SWlCNVBTSXROeUl2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweU5DSWdlVDBpTFRFMElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlMVE0ySWlCNVBTSXRNakVpTHo0OEwyYytQQzlrWldaelBqeHlaV04wSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU16VXdJaUJ5ZUQwaU1UQWlJR1pwYkd3OUlpTXlOVE16TWpZaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnphV3h2SWlCNFBTSTVPU0lnZVQwaU5UVWlMejQ4WnlCcFpEMGlZV3hzVUd4dmRDSWdZMnhwY0Mxd1lYUm9QU0oxY213b0kySnZjbVJsY2sxaGMyc3BJajQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaUxURTJOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXRNVFkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTUNJZ2VUMGlMVEV5TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpFek9DSWdlVDBpTFRFeU5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMHhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTA0TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXdJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMDBOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTAyT1NJZ2VUMGlMVFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamMybHNieUlnZUQwaU5EY2lJSGs5SWpVMUlpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOeWtpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTB4TXpnaUlIazlJak0ySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l6TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkwMk9TSWdlVDBpTnpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR0Z5ZEdsaGJFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlOellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXdJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlqRXhOaUlnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXhOVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJakUxTmlJZ0x6NDhMMmMrUEhKbFkzUWdlRDBpTUNJZ2VUMGlNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1DSWdlVDBpTVRRdU5TSWdabTl1ZEMxemFYcGxQU0l4TWlJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKemRHRnlkQ0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1FrVkJUaUJFWlhCdmMybDBQQzkwWlhoMFBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkwSkZRVTRpSUhnOUlqSTBNQ0lnZVQwaU5DSWdMejQ4Y21WamRDQjRQU0l3SWlCNVBTSXpNekFpSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU1qQWlJSEo0UFNJMUlpQm1hV3hzUFNJak1qUXlOREkwSWk4K1BIUmxlSFFnZUQwaU1USTNJaUI1UFNJek5ETWlJR1p2Ym5RdGMybDZaVDBpTVRBaUlHWnBiR3c5SWxkb2FYUmxJaUIwWlhoMExXRnVZMmh2Y2owaWJXbGtaR3hsSWlCbWIyNTBMV1poYldsc2VUMGlablYwZFhKaElqNDhkSE53WVc0K1BHRnVhVzFoZEdVZ1lYUjBjbWxpZFhSbFRtRnRaVDBpZUNJZ1puSnZiVDBpTXpjMUlpQjBiejBpTlRBaUlHUjFjajBpTVRCeklpQnlaWEJsWVhSRGIzVnVkRDBpYVc1a1pXWnBibWwwWlNJZ0x6NHdlR0psWVRBd01EQXdNamxoWkRGak56ZGtNMlExWkRJelltRXlaRGc0T1ROa1lqbGtNV1ZtWVdJOEwzUnpjR0Z1UGp3dmRHVjRkRDQ4ZEdWNGRDQjRQU0l4TWpjaUlIazlJak0wTXlJZ1ptOXVkQzF6YVhwbFBTSXhNQ0lnWm1sc2JEMGlWMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0p0YVdSa2JHVWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGp4MGMzQmhiajQ4WVc1cGJXRjBaU0JoZEhSeWFXSjFkR1ZPWVcxbFBTSjRJaUJtY205dFBTSTFNQ0lnZEc4OUlpMHlOelVpSUdSMWNqMGlNVEJ6SWlCeVpYQmxZWFJEYjNWdWREMGlhVzVrWldacGJtbDBaU0lnTHo0d2VHSmxZVEF3TURBd01qbGhaREZqTnpka00yUTFaREl6WW1FeVpEZzRPVE5rWWpsa01XVm1ZV0k4TDNSemNHRnVQand2ZEdWNGRENDhkR1Y0ZENCNFBTSXlNelVpSUhrOUlqRTBMalVpSUdadmJuUXRjMmw2WlQwaU1USWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGlaVzVrSWlCbWIyNTBMV1poYldsc2VUMGlablYwZFhKaElqNVRkR1Z0T2lBeVBDOTBaWGgwUGp3dmMzWm5QZz09In0= \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJCRUFOIn0sIHsgInRyYWl0X3R5cGUiOiAiVG9rZW4gQWRkcmVzcyIsICJ2YWx1ZSI6ICIweGJlYTAwMDAwMjlhZDFjNzdkM2Q1ZDIzYmEyZDg4OTNkYjlkMWVmYWIifSwgeyAidHJhaXRfdHlwZSI6ICJJZCIsICJ2YWx1ZSI6ICIweGJlYTAwMDAwMjlhZDFjNzdkM2Q1ZDIzYmEyZDg4OTNkYjlkMWVmYWIwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDIifSwgeyAidHJhaXRfdHlwZSI6ICJzdGVtIiwgImRpc3BsYXlfdHlwZSI6ICJudW1iZXIiLCAidmFsdWUiOiAyfSwgeyAidHJhaXRfdHlwZSI6ICJpbml0YWwgc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMTAwMDB9LCB7ICJ0cmFpdF90eXBlIjogImdyb3duIHN0YWxrIHBlciBCRFYiLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDIwMDB9LCB7ICJ0cmFpdF90eXBlIjogInN0YWxrIGdyb3duIHBlciBCRFYgcGVyIHNlYXNvbiIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMjAwMDAwMCwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OEwyYytQR2NnYVdROUluQmhjblJwWVd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0dGeWRHbGhiRXhsWVdaU2IzY2lJSGc5SWkwMk1DSWdlVDBpTVRRaUlHWnBiR3c5SWlOQk9FTTRNMEVpSUhSeVlXNXpabTl5YlQwaWMyTmhiR1VvTVM0MEtTSXZQand2Wno0OFp5QnBaRDBpYkdWaFppSStQSEJoZEdnZ1pEMGlUVEUzTVM0NE9EUWdNVEU0TGprNE0yRTBMamt6TWlBMExqa3pNaUF3SURBZ01TMHhMakF4T0NBeUxqWXdOaUEwTGpjeE5TQTBMamN4TlNBd0lEQWdNUzB4TGpnM09DQXhMalF6T1dNdExqUTJOUzR4T1RVdE1TNDNNelV1TnpJM0xUSXVNelkwTGpFM05pMHVNalEySURNdU1qazRMVEV1TlRreklEWXVOVEV5TFRJdU1qVXpJRGN1T1RVMFlUUXVOVE15SURRdU5UTXlJREFnTUNBeExTNHpNVE10TGprek0yTXRMakl4TVMwdU9UYzFMUzR3TXpndE1TNDNOak11TURjNExUSXVNamsxTGpJd01pMHVPVEl4TGpNMU15MHhMall4TWk0ME5qY3RNaTR4TkMweExqRTNOeTQyT1RRdE1pNDJOREl1TlRZNUxUTXVOVFU0TFM0eU56SXRMamM1TmkwdU56TXlMVEV1TURnekxURXVPVEl4TFM0M05ETXRNeTR3TXpRdU5EazRMakF4TVNBeExqa3pPUzR4TURrZ015NHlORGNnTVM0eE5qZGhOUzR4TXlBMUxqRXpJREFnTUNBeElERXVNakVnTVM0ME1UTmpMakUxT1MwdU56UXVNVGs1TFM0NU5UZ3VNak00TFRFdU1UYzVMakl3T1MweExqSXhNeTR6TWpJdE1TNDROekl1TWpjMExUSXVOekkwWVRjdU56TWdOeTQzTXlBd0lEQWdNQzB1T1RBNExUTXVNVGMzWXkwdU56Y3lMalF4TlMweExqYzRPUzR4T1RZdE1pNHpOemd0TGpNd05DMHVNek01TFM0eU9EY3RMalUxTmkwdU5qZ3lMUzQzTmpRdE1TNDJPVEpoTVRJdU56TTVJREV5TGpjek9TQXdJREFnTVMwdU1UYzJMVE11T1RBNVl5NDNPRGt1TmpBeklERXVORGNnTVM0d01Ua2dNUzQ1TXpjZ01TNHlPRE11T1RRMExqVXpOaUF4TGpNME5DNDJNemtnTVM0M05qRWdNUzR4TmpjdU1UVXlMakU1TXk0Mk5Ea3VPRFF5TGpVNE5pQXhMamMxTVMwdU1ERXhMakUzTWkwdU1EVXpMamM1TlMwdU5EWTBJREV1TWprellUWXVPRE1nTmk0NE15QXdJREFnTVNBeExqTTROQ0F5TGpJeU4yTXVNVFF1TXpZNExqSTBNaTQzTkRRdU16RXhJREV1TVRVdU1UQTNMUzR5TURjdU1qWXhMUzQwTXprdU5URXhMUzQzTWpJdU5EVXpMUzQxTVRNdU9EY3RMams1TWlBeExqWXdOQzB4TGpJNE5DNDJPRE10TGpJM01pQXhMakk0TFM0eU5Ea2dNUzQzTWpNdExqSXpOR0UxTGpNd01pQTFMak13TWlBd0lEQWdNU0F4TGpRNE5pNHlOek5hSWk4K1BDOW5QanhuSUdsa1BTSnphV3h2SWo0OGNHRjBhQ0JrUFNKTk5UY3VNVEE0SURjeExqSTVZeTR4T0RndE1URXVOalV6TFRFeUxqQXhMVEl4TGpNd015MHlOeTR5TkRNdE1qRXVOVFV5TFRFMUxqSXpOQzB1TWpVdE1qY3VOek0ySURndU9UazFMVEkzTGpreU15QXlNQzQyTkRrdExqRTROeUF4TVM0Mk5UUWdNVEl1TURFZ01qRXVNekEwSURJM0xqSTBOQ0F5TVM0MU5UTWdNVFV1TWpNekxqSTFJREkzTGpjek5TMDRMams1TlNBeU55NDVNakl0TWpBdU5qVmFJaUJtYVd4c1BTSWpOalkySWk4K1BIQmhkR2dnWkQwaVRTNDBOalFnTVRrdU5UUTBZeTQyT1RrZ01UWXVOVGcxSURFdU5DQXpNeTR4TmprZ01pNHdPVGdnTkRrdU56VXlMakF5TVNBeUxqTTRNUzQwT0NBMExqSTNPQzQ0T0RNZ05TNDFNemt1TWpjM0xqZzJMamMwTVNBeUxqSTNOU0F4TGpjM09DQXpMamcyTnk0ME9UUXVOelU1SURFdU1qRXlJREV1TnlBekxqQXdNaUF6TGpNek1pQXhMamN6T1NBeExqVTROaUF6TGpNMUlETXVNRFUySURVdU56TXlJRFF1TXprNElETXVNamt6SURFdU9EVTFJRFl1TVRVeElESXVNemsySURndU56a3hJREl1T0RrMklERXVPRFUxTGpNMUlEVXVNVFE1TGprME9DQTVMalE0T0M0MU5UWmhNekl1TnpBM0lETXlMamN3TnlBd0lEQWdNQ0E1TGpNeE5TMHlMakk0TjJNeExqZzJNaTB1TnpVNUlEUXVOalF5TFRFdU9URTNJRGN1TmpNekxUUXVOQ0F4TGpNME9DMHhMakV5SURNdU5EUTRMVEl1T0RrM0lEVXVNVGszTFRVdU9UVmhNakF1TVRFMElESXdMakV4TkNBd0lEQWdNQ0F5TGpJMUxUVXVPVGs0WXk0eU1TMHhOeTQxTlRJdU5ESXRNelV1TVRBMExqWXpNaTAxTWk0Mk5UZHNMVFUyTGpndU9UVXlhQzR3TURGYUlpQm1hV3hzUFNJalFqTkNNMEl6SWk4K1BIQmhkR2dnWkQwaVRUVTNMalE0SURFNUxqUTRNa00xTnk0Mk5EVWdPUzR5TkNBME5DNDVOemd1TnpJM0lESTVMakU0Tnk0ME5qZ2dNVE11TXprM0xqSXhMalEyTXlBNExqTXdNeTR5T1RnZ01UZ3VOVFEyTGpFek5DQXlPQzQzT0RnZ01USXVPQ0F6Tnk0eklESTRMalU1TVNBek55NDFObU14TlM0M09TNHlOVGdnTWpndU56STBMVGN1T0RNMUlESTRMamc0T1MweE9DNHdOemhhSWlCbWFXeHNQU0lqUTBORElpOCtQSEJoZEdnZ1pEMGlUVE13TGpNeE5DQTNMakV6TjJNdU1EQTVMUzQxTmpFdExqWTRMVEV1TURJNExURXVOVE00TFRFdU1EUXlMUzQ0TlRrdExqQXhOQzB4TGpVMk1pNDBNeTB4TGpVM01TNDVPVEV0TGpBeExqVTJNaTQyT0NBeExqQXlPQ0F4TGpVek9DQXhMakEwTWk0NE5Ua3VNREUxSURFdU5UWXlMUzQwTXlBeExqVTNMUzQ1T1ZvaUlHWnBiR3c5SWlNMk5qWWlMejQ4Y0dGMGFDQmtQU0pOTmk0ME1UUWdNamd1T0RsaE1UVXVOemMzSURFMUxqYzNOeUF3SURBZ01TMHlMakE1TXkweUxqRTBObU10TGpnMU5pMHhMakEyTXkweUxqUTFNeTB6TGpBNU15MHlMamszTlMwMkxqRXhNbUV4TVM0M05qVWdNVEV1TnpZMUlEQWdNQ0F4TFM0d09UTXRNeTR6TURkc01qVXVORE10T1M0NU56WmpMakEwTXk0eE5ESXVNVGc0TGpVMU5TNDJNRFF1T0RZNExqUTJMak0wTmk0NU5EY3VNelFnTVM0d09EWXVNek0wVERZdU5ERXpJREk0TGpnNE9IWXVNREF5V2lJZ1ptbHNiRDBpSTBVMlJUWkZOaUl2UGp4d1lYUm9JRzl3WVdOcGRIazlJaTR6TXlJZ1pEMGlUVEV1TkRjM0lERTJMakF5T1dNdU1qVXRMamt6TVM0M01EWXRNaTR5TlRnZ01TNDFOeTB6TGpZNU5TNDJOVFV0TVM0d09USWdNUzR5T1RJdE1TNDRNalVnTVM0M05pMHlMak0xT0M0MU9EUXRMalkyTlNBeExqYzNOaTB4TGprek5DQXpMalkzT1MwekxqSTVJREl1T1RVekxUSXVNVEExSURVdU5qazJMVE11TURVZ055NDNNak10TXk0M00yRXpOeTR6TlNBek55NHpOU0F3SURBZ01TQTJMalE0TlMweExqVTBOMncxTGpJME1pQTBMak14Tm1FeExqUTRJREV1TkRnZ01DQXdJREF0TVM0eU1UUXVPVFkzVERFdU5EZ2dNVFl1TUROb0xTNHdNREphSWlCbWFXeHNQU0lqT1RrNUlpOCtQSEJoZEdnZ2IzQmhZMmwwZVQwaUxqUTBJaUJrUFNKTk1TNDRNU0F5Tmk0MU16SmpMakl3Tmk0ME9UUXVORGcwSURFdU1EVXVPRFlnTVM0Mk0yRXhNQzR5TmpZZ01UQXVNalkySURBZ01DQXdJREl1TWpjNElESXVORGcyVERZdU5UVXlJRGM0TGpJeVlURTNMakkzTWlBeE55NHlOeklnTUNBd0lERXRNeTAzTGpReE0wd3hMamd4SURJMkxqVXpNbG9pSUdacGJHdzlJaU5GTmtVMlJUWWlMejQ4Y0dGMGFDQmtQU0p0TXpNdU1Ea3lJRFE1TGpRME1TMDJMak00TVNBeE5TNHlNVEZ6TFRZdU1EYzRMVEV4TGpFMU9TQTJMak00TVMweE5TNHlNVm9pSUdacGJHdzlJaU00UlRoRk9FVWlMejQ4Y0dGMGFDQmtQU0p0TWpZdU56STFJRFkwTGpnMU9DMHVNRGt4TFM0eE56VmpMUzR3TWpZdExqQTBPUzB5TGpZek5DMDBMamt5TXkwdU9EWTNMVGt1TXpjZ01TNHdOVGN0TWk0M01UY2dNeTQxTVRndE5DNDNNalVnTnk0ekxUVXVPVFEyYkM0eE9EY3RMakEyTVMwMkxqVXpJREUxTGpVMU1scHROaTR5TVRJdE1UVXVNalk0WXkwekxqWXlNU0F4TGpJeE55MDFMams1TVNBekxqRTJPQzAzTGpBeU1pQTFMamM1T0MweExqVXpPQ0F6TGprd09DNHpOVFVnT0M0eE5qWXVOemc0SURrdU1EVTBiRFl1TWpNMExURTBMamcxTWxwTk1qZ3VNRGt6SURZekxqY3pOMncwTGpRNE5DMHhNQzQ0TjNNM0xqTTJOU0EyTGpNek55MDBMalE0TkNBeE1DNDROMW9pSUdacGJHdzlJaU00UlRoRk9FVWlMejQ4TDJjK1BHY2dhV1E5SWtKRlFVNGlQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTBOa0k1TlRVaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RjZ01TNHlOalV0TXk0MU1EUWdPUzR6TmxNdU1qazRJRE11T1RrNUlEY3VOamczSURFdU1qWTJXbTB0TWk0Mk9URWdPQzQzT0NBeUxqUTJNaTAyTGpZNU1YTTBMalV6T0NBekxqWTNMVEl1TkRZeUlEWXVOamt4V2lJZ1ptbHNiRDBpSTJabVppSXZQand2Wno0OFp5QnBaRDBpUWtWQlRqTkRVbFlpUGp4eVpXTjBJSGs5SWk0MUlpQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnM0lERXVOelkwTFRNdU5UQTBJRGt1TXpaVExqSTVPQ0EwTGpRNU9TQTNMalk0TnlBeExqYzJOVm9pSUdacGJHdzlJaU5tWm1ZaUx6NDhjR0YwYUNCa1BTSk5PQzR4TXpJZ09DNHdOemhqTFM0ME5qWXVOalF0TVM0eU9UY2dNUzR6TWpNdE1pNDJPVFVnTVM0NU9USnNNaTR4TWpZdE5TNDNOemRqTGpBNE9TNHdPUzR4T1RNdU1qQTBMak11TXpNNExqTXdNeTR6TnpVdU5qSTFMamc1TVM0M05EUWdNUzQwT0RRdU1URTNMalU0TXk0d05DQXhMakkxTXkwdU5EYzFJREV1T1RZeldpSWdabWxzYkQwaWRYSnNLQ05oS1NJZ2MzUnliMnRsUFNJalptWm1JaUJ6ZEhKdmEyVXRkMmxrZEdnOUlpNDFJaTgrUEdSbFpuTStQR3hwYm1WaGNrZHlZV1JwWlc1MElHbGtQU0poSWlCNE1UMGlOaTQ1TlNJZ2VURTlJak11T0RVeklpQjRNajBpTmk0NU5TSWdlVEk5SWpFd0xqVTBOQ0lnWjNKaFpHbGxiblJWYm1sMGN6MGlkWE5sY2xOd1lXTmxUMjVWYzJVaVBqeHpkRzl3SUhOMGIzQXRZMjlzYjNJOUlpTTRNakF5TURJaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWk0eE9ESWlJSE4wYjNBdFkyOXNiM0k5SWlOR056RkZNRFVpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJaTQxTVRZaUlITjBiM0F0WTI5c2IzSTlJaU5HTUVZMU1EY2lMejQ4YzNSdmNDQnZabVp6WlhROUlpNDNNelFpSUhOMGIzQXRZMjlzYjNJOUlpTTROVU5FTnpVaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWpFaUlITjBiM0F0WTI5c2IzSTlJaU13TWpsRVJrSWlMejQ4TDJ4cGJtVmhja2R5WVdScFpXNTBQand2WkdWbWN6NDhMMmMrUEdjZ2FXUTlJblZ5UWtWQlRpSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6ZEdOVFV6TXlJdlBqeHdZWFJvSUdROUltMDNMalk0TnlBeExqSTJOUzB6TGpVd05DQTVMak0yVXk0eU9UZ2dNeTQ1T1RrZ055NDJPRGNnTVM0eU5qWmFiUzB5TGpZNU1TQTRMamM0SURJdU5EWXlMVFl1TmpreGN6UXVOVE00SURNdU5qY3RNaTQwTmpJZ05pNDJPVEZhSWlCbWFXeHNQU0lqWm1abUlpOCtQQzluUGp4bklHbGtQU0pDUlVGT1JWUklJajQ4Y21WamRDQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnMElERXVNalkxTFRNdU5UQTFJRGt1TXpaakxqQXdNeUF3TFRNdU9EZzBMVFl1TmpJMUlETXVOVEExTFRrdU16WmFJaUJtYVd4c1BTSWpabVptSWk4K1BIQmhkR2dnWkQwaVRUZ3VPVFV5SURZdU9UZzJZUzR3TmpNdU1EWXpJREFnTUNBeExTNHdNakl1TURBell5MHVOekV1TVRNdE1TNDBNalF1TWpVMUxUSXVNVE0wTGpNNE1TMHVNamd4TGpBMU1pMHVOVFkxTGpFd015MHVPRFEyTGpFMU1tRXVNRE0yTGpBek5pQXdJREFnTVMwdU1ESTJJREJzTWk0eE5DMDFMall5TlM0d01EUXRMakF3TTJNdU1qazNJREV1TnpBeUxqVTVJRE11TXprMExqZzROQ0ExTGpBNU1scHRMUzR4T0RjdU5EYzRZeTB4TGpJMk5pNDROVGt0TWk0MU16RWdNUzQzTWpFdE15NDRJREl1TlRoc0xqYzRNUzB5TGpBMU5HTXVNREEzTGpBd05DNHdNVE1nTUNBdU1ESXpJREFnTGpjMU9TMHVNVE15SURFdU5URTBMUzR5TmpnZ01pNHlOeTB1Tkd3dU5qazNMUzR4TWpZdU1ETXRMakF3Tm1NdExqQXdOQzR3TURNZ01DQXVNREEySURBZ0xqQXdObG9pSUdacGJHdzlJaU13TURBaUx6NDhMMmMrUEdjZ2FXUTlJblZ5UWtWQlRrVlVTQ0krUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJemRHTlRVek15SXZQanh3WVhSb0lHUTlJbTAzTGpZNE5DQXhMakkyTlMwekxqVXdOU0E1TGpNMll5NHdNRE1nTUMwekxqZzROQzAyTGpZeU5TQXpMalV3TlMwNUxqTTJXaUlnWm1sc2JEMGlJMlptWmlJdlBqeHdZWFJvSUdROUlrMDRMamsxTWlBMkxqazRObUV1TURZekxqQTJNeUF3SURBZ01TMHVNREl5TGpBd00yTXRMamN4TGpFekxURXVOREkwTGpJMU5TMHlMakV6TkM0ek9ERXRMakk0TVM0d05USXRMalUyTlM0eE1ETXRMamcwTmk0eE5USmhMakF6Tmk0d016WWdNQ0F3SURFdExqQXlOaUF3YkRJdU1UUXROUzQyTWpVdU1EQTBMUzR3TUROakxqSTVOeUF4TGpjd01pNDFPU0F6TGpNNU5DNDRPRFFnTlM0d09USmFiUzB1TVRnM0xqUTNPR010TVM0eU5qWXVPRFU1TFRJdU5UTXhJREV1TnpJeExUTXVPQ0F5TGpVNGJDNDNPREV0TWk0d05UUmpMakF3Tnk0d01EUXVNREV6SURBZ0xqQXlNeUF3SUM0M05Ua3RMakV6TWlBeExqVXhOQzB1TWpZNElESXVNamN0TGpSc0xqWTVOeTB1TVRJMkxqQXpMUzR3TURaakxTNHdNRFF1TURBeklEQWdMakF3TmlBd0lDNHdNRFphSWlCbWFXeHNQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0pzWldGbVVtOTNJajQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5zWldGbUlpQjRQU0l3SWlCNVBTSXdJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTFRFeUlpQjVQU0l0TnlJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1lpSUhnOUlpMHlOQ0lnZVQwaUxURTBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTFRNMklpQjVQU0l0TWpFaUx6NDhMMmMrUEM5a1pXWnpQanh5WldOMElIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNelV3SWlCeWVEMGlNVEFpSUdacGJHdzlJaU15TlRNek1qWWlMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU56YVd4dklpQjRQU0k1T1NJZ2VUMGlOVFVpTHo0OFp5QnBaRDBpWVd4c1VHeHZkQ0lnWTJ4cGNDMXdZWFJvUFNKMWNtd29JMkp2Y21SbGNrMWhjMnNwSWo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTAyT1NJZ2VUMGlMVEUyTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l0TVRZMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU1DSWdlVDBpTFRFeU5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqRXpPQ0lnZVQwaUxURXlOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTB4TXpnaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWkwNE5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqWTVJaUI1UFNJdE9EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXRORFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l3SWlCNVBTSXRORFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l4TXpnaUlIazlJaTAwTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkwMk9TSWdlVDBpTFRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjMmxzYnlJZ2VEMGlORGNpSUhrOUlqVTFJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TnlraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkweE16Z2lJSGs5SWpNMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaU56WWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0dGeWRHbGhiRXhsWVdaUWJHOTBJaUI0UFNJMk9TSWdlVDBpTnpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l3SWlCNVBTSXhNVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l4TXpnaUlIazlJakV4TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l4TlRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpFMU5pSWdMejQ4TDJjK1BISmxZM1FnZUQwaU1DSWdlVDBpTUNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXlNQ0lnY25nOUlqVWlJR1pwYkd3OUlpTXlOREkwTWpRaUx6NDhkR1Y0ZENCNFBTSXhNQ0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSnpkR0Z5ZENJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStRa1ZCVGlCRVpYQnZjMmwwUEM5MFpYaDBQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMEpGUVU0aUlIZzlJakkwTUNJZ2VUMGlOQ0lnTHo0OGNtVmpkQ0I0UFNJd0lpQjVQU0l6TXpBaUlIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNakFpSUhKNFBTSTFJaUJtYVd4c1BTSWpNalF5TkRJMElpOCtQSFJsZUhRZ2VEMGlNVEkzSWlCNVBTSXpORE1pSUdadmJuUXRjMmw2WlQwaU1UQWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGliV2xrWkd4bElpQm1iMjUwTFdaaGJXbHNlVDBpWm5WMGRYSmhJajQ4ZEhOd1lXNCtQR0Z1YVcxaGRHVWdZWFIwY21saWRYUmxUbUZ0WlQwaWVDSWdabkp2YlQwaU16YzFJaUIwYnowaU5UQWlJR1IxY2owaU1UQnpJaUJ5WlhCbFlYUkRiM1Z1ZEQwaWFXNWtaV1pwYm1sMFpTSWdMejR3ZUdKbFlUQXdNREF3TWpsaFpERmpOemRrTTJRMVpESXpZbUV5WkRnNE9UTmtZamxrTVdWbVlXSThMM1J6Y0dGdVBqd3ZkR1Y0ZEQ0OGRHVjRkQ0I0UFNJeE1qY2lJSGs5SWpNME15SWdabTl1ZEMxemFYcGxQU0l4TUNJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKdGFXUmtiR1VpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBqeDBjM0JoYmo0OFlXNXBiV0YwWlNCaGRIUnlhV0oxZEdWT1lXMWxQU0o0SWlCbWNtOXRQU0kxTUNJZ2RHODlJaTB5TnpVaUlHUjFjajBpTVRCeklpQnlaWEJsWVhSRGIzVnVkRDBpYVc1a1pXWnBibWwwWlNJZ0x6NHdlR0psWVRBd01EQXdNamxoWkRGak56ZGtNMlExWkRJelltRXlaRGc0T1ROa1lqbGtNV1ZtWVdJOEwzUnpjR0Z1UGp3dmRHVjRkRDQ4ZEdWNGRDQjRQU0l5TXpVaUlIazlJakUwTGpVaUlHWnZiblF0YzJsNlpUMGlNVElpSUdacGJHdzlJbGRvYVhSbElpQjBaWGgwTFdGdVkyaHZjajBpWlc1a0lpQm1iMjUwTFdaaGJXbHNlVDBpWm5WMGRYSmhJajVUZEdWdE9pQXlQQzkwWlhoMFBqd3ZjM1puUGc9PSJ9 \ No newline at end of file diff --git a/protocol/test/data/base64EncodedImageBean3Crv.txt b/protocol/test/data/base64EncodedImageBean3Crv.txt index e3a0c1c14f..79776d64c2 100644 --- a/protocol/test/data/base64EncodedImageBean3Crv.txt +++ b/protocol/test/data/base64EncodedImageBean3Crv.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IEJFQU4zQ1JWXG5Ub2tlbiBBZGRyZXNzOiAweGM5YzMyY2QxNmJmN2VmYjg1ZmYxNGUwYzg2MDNjYzkwZjZmMmVlNDlcbklkOiAweGM5YzMyY2QxNmJmN2VmYjg1ZmYxNGUwYzg2MDNjYzkwZjZmMmVlNDkwMDAwMDAwMDAwMDAwMDAwMDAwMDAyMDBcbnN0ZW06IDUxMlxuaW5pdGFsIHN0YWxrIHBlciBCRFY6IDEwMDAwXG5ncm93biBzdGFsayBwZXIgQkRWOiAzNDkyXG5zdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb246IDQwMDAwMDBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCamJHRnpjejBpYzNablFtOWtlU0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJek5UQWlJSFpwWlhkQ2IzZzlJakFnTUNBeU5UVWdNelV3SWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhodGJHNXpPbmhzYVc1clBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJajQ4WkdWbWN6NDhaeUJwWkQwaWNHeHZkQ0krUEhCaGRHZ2daRDBpVFRjNUxqVTNNamdnTVRJNUxqSTJOVXd4TWpjdU5EWTVJREUxTmk0NE16Tk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UQXhMalk1TjB3M09TNDFOekk0SURFeU9TNHlOalZhSWlCbWFXeHNQU0lqT1RRMFFUSTNJaTgrUEhCaGRHZ2daRDBpVFRjNUxqVXpNeklnTVRNekxqUXlOa3czT1M0MU56STNJREV5T1M0eU5qVk1NVEkzTGpRMk9TQXhOVFl1T0RNelRERXlOeTQxTURjZ01UWXdMamt3T0V3M09TNDFNek15SURFek15NDBNalphSWlCbWFXeHNQU0lqTnpVek9URkdJaTgrUEhCaGRHZ2daRDBpVFRFM05TNDBOamNnTVRNekxqUk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UVTJMamd6TTB3eE1qY3VOVEEzSURFMk1DNDVNRGhNTVRjMUxqUTJOeUF4TXpNdU5Gb2lJR1pwYkd3OUlpTTJOek16TVVVaUx6NDhMMmMrUEdjZ2FXUTlJbVoxYkd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUWXdJaUI1UFNJeE5DSWdabWxzYkQwaUkwRTRRemd6UVNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUY3pJaUI1UFNJeU1TSWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKbGJYQjBlVkJzYjNRaVBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQnNiM1FpSUhnOUlpMHpOU0lnZVQwaU1DSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSndZWEowYVdGc1RHVmhabEp2ZHlJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaU1DSWdlVDBpTUNJdlBqd3ZaejQ4WnlCcFpEMGljR0Z5ZEdsaGJFeGxZV1pRYkc5MElqNDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTndiRzkwSWlCNFBTSXRNelVpSUhrOUlqQWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQmhjblJwWVd4TVpXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp3dlp6NDhaeUJwWkQwaWJHVmhaaUkrUEhCaGRHZ2daRDBpVFRFM01TNDRPRFFnTVRFNExqazRNMkUwTGprek1pQTBMamt6TWlBd0lEQWdNUzB4TGpBeE9DQXlMall3TmlBMExqY3hOU0EwTGpjeE5TQXdJREFnTVMweExqZzNPQ0F4TGpRek9XTXRMalEyTlM0eE9UVXRNUzQzTXpVdU56STNMVEl1TXpZMExqRTNOaTB1TWpRMklETXVNams0TFRFdU5Ua3pJRFl1TlRFeUxUSXVNalV6SURjdU9UVTBZVFF1TlRNeUlEUXVOVE15SURBZ01DQXhMUzR6TVRNdExqa3pNMk10TGpJeE1TMHVPVGMxTFM0d016Z3RNUzQzTmpNdU1EYzRMVEl1TWprMUxqSXdNaTB1T1RJeExqTTFNeTB4TGpZeE1pNDBOamN0TWk0eE5DMHhMakUzTnk0Mk9UUXRNaTQyTkRJdU5UWTVMVE11TlRVNExTNHlOekl0TGpjNU5pMHVOek15TFRFdU1EZ3pMVEV1T1RJeExTNDNORE10TXk0d016UXVORGs0TGpBeE1TQXhMamt6T1M0eE1Ea2dNeTR5TkRjZ01TNHhOamRoTlM0eE15QTFMakV6SURBZ01DQXhJREV1TWpFZ01TNDBNVE5qTGpFMU9TMHVOelF1TVRrNUxTNDVOVGd1TWpNNExURXVNVGM1TGpJd09TMHhMakl4TXk0ek1qSXRNUzQ0TnpJdU1qYzBMVEl1TnpJMFlUY3VOek1nTnk0M015QXdJREFnTUMwdU9UQTRMVE11TVRjM1l5MHVOemN5TGpReE5TMHhMamM0T1M0eE9UWXRNaTR6TnpndExqTXdOQzB1TXpNNUxTNHlPRGN0TGpVMU5pMHVOamd5TFM0M05qUXRNUzQyT1RKaE1USXVOek01SURFeUxqY3pPU0F3SURBZ01TMHVNVGMyTFRNdU9UQTVZeTQzT0RrdU5qQXpJREV1TkRjZ01TNHdNVGtnTVM0NU16Y2dNUzR5T0RNdU9UUTBMalV6TmlBeExqTTBOQzQyTXprZ01TNDNOakVnTVM0eE5qY3VNVFV5TGpFNU15NDJORGt1T0RReUxqVTROaUF4TGpjMU1TMHVNREV4TGpFM01pMHVNRFV6TGpjNU5TMHVORFkwSURFdU1qa3pZVFl1T0RNZ05pNDRNeUF3SURBZ01TQXhMak00TkNBeUxqSXlOMk11TVRRdU16WTRMakkwTWk0M05EUXVNekV4SURFdU1UVXVNVEEzTFM0eU1EY3VNall4TFM0ME16a3VOVEV4TFM0M01qSXVORFV6TFM0MU1UTXVPRGN0TGprNU1pQXhMall3TkMweExqSTROQzQyT0RNdExqSTNNaUF4TGpJNExTNHlORGtnTVM0M01qTXRMakl6TkdFMUxqTXdNaUExTGpNd01pQXdJREFnTVNBeExqUTROaTR5TnpOYUlpOCtQQzluUGp4bklHbGtQU0p6YVd4dklqNDhjR0YwYUNCa1BTSk5OVGN1TVRBNElEY3hMakk1WXk0eE9EZ3RNVEV1TmpVekxURXlMakF4TFRJeExqTXdNeTB5Tnk0eU5ETXRNakV1TlRVeUxURTFMakl6TkMwdU1qVXRNamN1TnpNMklEZ3VPVGsxTFRJM0xqa3lNeUF5TUM0Mk5Ea3RMakU0TnlBeE1TNDJOVFFnTVRJdU1ERWdNakV1TXpBMElESTNMakkwTkNBeU1TNDFOVE1nTVRVdU1qTXpMakkxSURJM0xqY3pOUzA0TGprNU5TQXlOeTQ1TWpJdE1qQXVOalZhSWlCbWFXeHNQU0lqTmpZMklpOCtQSEJoZEdnZ1pEMGlUUzQwTmpRZ01Ua3VOVFEwWXk0Mk9Ua2dNVFl1TlRnMUlERXVOQ0F6TXk0eE5qa2dNaTR3T1RnZ05Ea3VOelV5TGpBeU1TQXlMak00TVM0ME9DQTBMakkzT0M0NE9ETWdOUzQxTXprdU1qYzNMamcyTGpjME1TQXlMakkzTlNBeExqYzNPQ0F6TGpnMk55NDBPVFF1TnpVNUlERXVNakV5SURFdU55QXpMakF3TWlBekxqTXpNaUF4TGpjek9TQXhMalU0TmlBekxqTTFJRE11TURVMklEVXVOek15SURRdU16azRJRE11TWpreklERXVPRFUxSURZdU1UVXhJREl1TXprMklEZ3VOemt4SURJdU9EazJJREV1T0RVMUxqTTFJRFV1TVRRNUxqazBPQ0E1TGpRNE9DNDFOVFpoTXpJdU56QTNJRE15TGpjd055QXdJREFnTUNBNUxqTXhOUzB5TGpJNE4yTXhMamcyTWkwdU56VTVJRFF1TmpReUxURXVPVEUzSURjdU5qTXpMVFF1TkNBeExqTTBPQzB4TGpFeUlETXVORFE0TFRJdU9EazNJRFV1TVRrM0xUVXVPVFZoTWpBdU1URTBJREl3TGpFeE5DQXdJREFnTUNBeUxqSTFMVFV1T1RrNFl5NHlNUzB4Tnk0MU5USXVOREl0TXpVdU1UQTBMall6TWkwMU1pNDJOVGRzTFRVMkxqZ3VPVFV5YUM0d01ERmFJaUJtYVd4c1BTSWpRak5DTTBJeklpOCtQSEJoZEdnZ1pEMGlUVFUzTGpRNElERTVMalE0TWtNMU55NDJORFVnT1M0eU5DQTBOQzQ1TnpndU56STNJREk1TGpFNE55NDBOamdnTVRNdU16azNMakl4TGpRMk15QTRMak13TXk0eU9UZ2dNVGd1TlRRMkxqRXpOQ0F5T0M0M09EZ2dNVEl1T0NBek55NHpJREk0TGpVNU1TQXpOeTQxTm1NeE5TNDNPUzR5TlRnZ01qZ3VOekkwTFRjdU9ETTFJREk0TGpnNE9TMHhPQzR3TnpoYUlpQm1hV3hzUFNJalEwTkRJaTgrUEhCaGRHZ2daRDBpVFRNd0xqTXhOQ0EzTGpFek4yTXVNREE1TFM0MU5qRXRMalk0TFRFdU1ESTRMVEV1TlRNNExURXVNRFF5TFM0NE5Ua3RMakF4TkMweExqVTJNaTQwTXkweExqVTNNUzQ1T1RFdExqQXhMalUyTWk0Mk9DQXhMakF5T0NBeExqVXpPQ0F4TGpBME1pNDROVGt1TURFMUlERXVOVFl5TFM0ME15QXhMalUzTFM0NU9Wb2lJR1pwYkd3OUlpTTJOallpTHo0OGNHRjBhQ0JrUFNKTk5pNDBNVFFnTWpndU9EbGhNVFV1TnpjM0lERTFMamMzTnlBd0lEQWdNUzB5TGpBNU15MHlMakUwTm1NdExqZzFOaTB4TGpBMk15MHlMalExTXkwekxqQTVNeTB5TGprM05TMDJMakV4TW1FeE1TNDNOalVnTVRFdU56WTFJREFnTUNBeExTNHdPVE10TXk0ek1EZHNNalV1TkRNdE9TNDVOelpqTGpBME15NHhOREl1TVRnNExqVTFOUzQyTURRdU9EWTRMalEyTGpNME5pNDVORGN1TXpRZ01TNHdPRFl1TXpNMFREWXVOREV6SURJNExqZzRPSFl1TURBeVdpSWdabWxzYkQwaUkwVTJSVFpGTmlJdlBqeHdZWFJvSUc5d1lXTnBkSGs5SWk0ek15SWdaRDBpVFRFdU5EYzNJREUyTGpBeU9XTXVNalV0TGprek1TNDNNRFl0TWk0eU5UZ2dNUzQxTnkwekxqWTVOUzQyTlRVdE1TNHdPVElnTVM0eU9USXRNUzQ0TWpVZ01TNDNOaTB5TGpNMU9DNDFPRFF0TGpZMk5TQXhMamMzTmkweExqa3pOQ0F6TGpZM09TMHpMakk1SURJdU9UVXpMVEl1TVRBMUlEVXVOamsyTFRNdU1EVWdOeTQzTWpNdE15NDNNMkV6Tnk0ek5TQXpOeTR6TlNBd0lEQWdNU0EyTGpRNE5TMHhMalUwTjJ3MUxqSTBNaUEwTGpNeE5tRXhMalE0SURFdU5EZ2dNQ0F3SURBdE1TNHlNVFF1T1RZM1RERXVORGdnTVRZdU1ETm9MUzR3TURKYUlpQm1hV3hzUFNJak9UazVJaTgrUEhCaGRHZ2diM0JoWTJsMGVUMGlMalEwSWlCa1BTSk5NUzQ0TVNBeU5pNDFNekpqTGpJd05pNDBPVFF1TkRnMElERXVNRFV1T0RZZ01TNDJNMkV4TUM0eU5qWWdNVEF1TWpZMklEQWdNQ0F3SURJdU1qYzRJREl1TkRnMlREWXVOVFV5SURjNExqSXlZVEUzTGpJM01pQXhOeTR5TnpJZ01DQXdJREV0TXkwM0xqUXhNMHd4TGpneElESTJMalV6TWxvaUlHWnBiR3c5SWlORk5rVTJSVFlpTHo0OGNHRjBhQ0JrUFNKdE16TXVNRGt5SURRNUxqUTBNUzAyTGpNNE1TQXhOUzR5TVRGekxUWXVNRGM0TFRFeExqRTFPU0EyTGpNNE1TMHhOUzR5TVZvaUlHWnBiR3c5SWlNNFJUaEZPRVVpTHo0OGNHRjBhQ0JrUFNKdE1qWXVOekkxSURZMExqZzFPQzB1TURreExTNHhOelZqTFM0d01qWXRMakEwT1MweUxqWXpOQzAwTGpreU15MHVPRFkzTFRrdU16Y2dNUzR3TlRjdE1pNDNNVGNnTXk0MU1UZ3ROQzQzTWpVZ055NHpMVFV1T1RRMmJDNHhPRGN0TGpBMk1TMDJMalV6SURFMUxqVTFNbHB0Tmk0eU1USXRNVFV1TWpZNFl5MHpMall5TVNBeExqSXhOeTAxTGprNU1TQXpMakUyT0MwM0xqQXlNaUExTGpjNU9DMHhMalV6T0NBekxqa3dPQzR6TlRVZ09DNHhOall1TnpnNElEa3VNRFUwYkRZdU1qTTBMVEUwTGpnMU1scE5Namd1TURreklEWXpMamN6TjJ3MExqUTROQzB4TUM0NE4zTTNMak0yTlNBMkxqTXpOeTAwTGpRNE5DQXhNQzQ0TjFvaUlHWnBiR3c5SWlNNFJUaEZPRVVpTHo0OEwyYytQR2NnYVdROUlrSkZRVTRpUGp4eVpXTjBJSGRwWkhSb1BTSXhNaUlnYUdWcFoyaDBQU0l4TWlJZ2NuZzlJallpSUdacGJHdzlJaU0wTmtJNU5UVWlMejQ4Y0dGMGFDQmtQU0p0Tnk0Mk9EY2dNUzR5TmpVdE15NDFNRFFnT1M0ek5sTXVNams0SURNdU9UazVJRGN1TmpnM0lERXVNalkyV20wdE1pNDJPVEVnT0M0M09DQXlMalEyTWkwMkxqWTVNWE0wTGpVek9DQXpMalkzTFRJdU5EWXlJRFl1TmpreFdpSWdabWxzYkQwaUkyWm1aaUl2UGp3dlp6NDhaeUJwWkQwaVFrVkJUak5EVWxZaVBqeHlaV04wSUhrOUlpNDFJaUIzYVdSMGFEMGlNVElpSUdobGFXZG9kRDBpTVRJaUlISjRQU0kySWlCbWFXeHNQU0lqTkRaQ09UVTFJaTgrUEhCaGRHZ2daRDBpYlRjdU5qZzNJREV1TnpZMExUTXVOVEEwSURrdU16WlRMakk1T0NBMExqUTVPU0EzTGpZNE55QXhMamMyTlZvaUlHWnBiR3c5SWlObVptWWlMejQ4Y0dGMGFDQmtQU0pOT0M0eE16SWdPQzR3TnpoakxTNDBOall1TmpRdE1TNHlPVGNnTVM0ek1qTXRNaTQyT1RVZ01TNDVPVEpzTWk0eE1qWXROUzQzTnpkakxqQTRPUzR3T1M0eE9UTXVNakEwTGpNdU16TTRMak13TXk0ek56VXVOakkxTGpnNU1TNDNORFFnTVM0ME9EUXVNVEUzTGpVNE15NHdOQ0F4TGpJMU15MHVORGMxSURFdU9UWXpXaUlnWm1sc2JEMGlkWEpzS0NOaEtTSWdjM1J5YjJ0bFBTSWpabVptSWlCemRISnZhMlV0ZDJsa2RHZzlJaTQxSWk4K1BHUmxabk0rUEd4cGJtVmhja2R5WVdScFpXNTBJR2xrUFNKaElpQjRNVDBpTmk0NU5TSWdlVEU5SWpNdU9EVXpJaUI0TWowaU5pNDVOU0lnZVRJOUlqRXdMalUwTkNJZ1ozSmhaR2xsYm5SVmJtbDBjejBpZFhObGNsTndZV05sVDI1VmMyVWlQanh6ZEc5d0lITjBiM0F0WTI5c2IzSTlJaU00TWpBeU1ESWlMejQ4YzNSdmNDQnZabVp6WlhROUlpNHhPRElpSUhOMGIzQXRZMjlzYjNJOUlpTkdOekZGTURVaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWk0MU1UWWlJSE4wYjNBdFkyOXNiM0k5SWlOR01FWTFNRGNpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJaTQzTXpRaUlITjBiM0F0WTI5c2IzSTlJaU00TlVORU56VWlMejQ4YzNSdmNDQnZabVp6WlhROUlqRWlJSE4wYjNBdFkyOXNiM0k5SWlNd01qbEVSa0lpTHo0OEwyeHBibVZoY2tkeVlXUnBaVzUwUGp3dlpHVm1jejQ4TDJjK1BHY2dhV1E5SW5WeVFrVkJUaUkrUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJemRHTlRVek15SXZQanh3WVhSb0lHUTlJbTAzTGpZNE55QXhMakkyTlMwekxqVXdOQ0E1TGpNMlV5NHlPVGdnTXk0NU9Ua2dOeTQyT0RjZ01TNHlOalphYlMweUxqWTVNU0E0TGpjNElESXVORFl5TFRZdU5qa3hjelF1TlRNNElETXVOamN0TWk0ME5qSWdOaTQyT1RGYUlpQm1hV3hzUFNJalptWm1JaTgrUEM5blBqeG5JR2xrUFNKQ1JVRk9SVlJJSWo0OGNtVmpkQ0IzYVdSMGFEMGlNVElpSUdobGFXZG9kRDBpTVRJaUlISjRQU0kySWlCbWFXeHNQU0lqTkRaQ09UVTFJaTgrUEhCaGRHZ2daRDBpYlRjdU5qZzBJREV1TWpZMUxUTXVOVEExSURrdU16WmpMakF3TXlBd0xUTXVPRGcwTFRZdU5qSTFJRE11TlRBMUxUa3VNelphSWlCbWFXeHNQU0lqWm1abUlpOCtQSEJoZEdnZ1pEMGlUVGd1T1RVeUlEWXVPVGcyWVM0d05qTXVNRFl6SURBZ01DQXhMUzR3TWpJdU1EQXpZeTB1TnpFdU1UTXRNUzQwTWpRdU1qVTFMVEl1TVRNMExqTTRNUzB1TWpneExqQTFNaTB1TlRZMUxqRXdNeTB1T0RRMkxqRTFNbUV1TURNMkxqQXpOaUF3SURBZ01TMHVNREkySURCc01pNHhOQzAxTGpZeU5TNHdNRFF0TGpBd00yTXVNamszSURFdU56QXlMalU1SURNdU16azBMamc0TkNBMUxqQTVNbHB0TFM0eE9EY3VORGM0WXkweExqSTJOaTQ0TlRrdE1pNDFNekVnTVM0M01qRXRNeTQ0SURJdU5UaHNMamM0TVMweUxqQTFOR011TURBM0xqQXdOQzR3TVRNZ01DQXVNREl6SURBZ0xqYzFPUzB1TVRNeUlERXVOVEUwTFM0eU5qZ2dNaTR5TnkwdU5Hd3VOamszTFM0eE1qWXVNRE10TGpBd05tTXRMakF3TkM0d01ETWdNQ0F1TURBMklEQWdMakF3TmxvaUlHWnBiR3c5SWlNd01EQWlMejQ4TDJjK1BHY2dhV1E5SW5WeVFrVkJUa1ZVU0NJK1BISmxZM1FnZDJsa2RHZzlJakV5SWlCb1pXbG5hSFE5SWpFeUlpQnllRDBpTmlJZ1ptbHNiRDBpSXpkR05UVXpNeUl2UGp4d1lYUm9JR1E5SW0wM0xqWTROQ0F4TGpJMk5TMHpMalV3TlNBNUxqTTJZeTR3TURNZ01DMHpMamc0TkMwMkxqWXlOU0F6TGpVd05TMDVMak0yV2lJZ1ptbHNiRDBpSTJabVppSXZQanh3WVhSb0lHUTlJazA0TGprMU1pQTJMams0Tm1FdU1EWXpMakEyTXlBd0lEQWdNUzB1TURJeUxqQXdNMk10TGpjeExqRXpMVEV1TkRJMExqSTFOUzB5TGpFek5DNHpPREV0TGpJNE1TNHdOVEl0TGpVMk5TNHhNRE10TGpnME5pNHhOVEpoTGpBek5pNHdNellnTUNBd0lERXRMakF5TmlBd2JESXVNVFF0TlM0Mk1qVXVNREEwTFM0d01ETmpMakk1TnlBeExqY3dNaTQxT1NBekxqTTVOQzQ0T0RRZ05TNHdPVEphYlMwdU1UZzNMalEzT0dNdE1TNHlOall1T0RVNUxUSXVOVE14SURFdU56SXhMVE11T0NBeUxqVTRiQzQzT0RFdE1pNHdOVFJqTGpBd055NHdNRFF1TURFeklEQWdMakF5TXlBd0lDNDNOVGt0TGpFek1pQXhMalV4TkMwdU1qWTRJREl1TWpjdExqUnNMalk1TnkwdU1USTJMakF6TFM0d01EWmpMUzR3TURRdU1EQXpJREFnTGpBd05pQXdJQzR3TURaYUlpQm1hV3hzUFNJak1EQXdJaTgrUEM5blBqeG5JR2xrUFNKc1pXRm1VbTkzSWo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1JaUI0UFNJd0lpQjVQU0l3SWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaUxURXlJaUI1UFNJdE55SXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB5TkNJZ2VUMGlMVEUwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaUxUTTJJaUI1UFNJdE1qRWlMejQ4TDJjK1BDOWtaV1p6UGp4eVpXTjBJSGRwWkhSb1BTSXlOVFVpSUdobGFXZG9kRDBpTXpVd0lpQnllRDBpTVRBaUlHWnBiR3c5SWlNeU5UTXpNallpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOemFXeHZJaUI0UFNJNU9TSWdlVDBpTlRVaUx6NDhaeUJwWkQwaVlXeHNVR3h2ZENJZ1kyeHBjQzF3WVhSb1BTSjFjbXdvSTJKdmNtUmxjazFoYzJzcElqNDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkwMk9TSWdlVDBpTFRFMk5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqWTVJaUI1UFNJdE1UWTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNQ0lnZVQwaUxURXlOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJakV6T0NJZ2VUMGlMVEV5TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkweE16Z2lJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXROamtpSUhrOUlpMDROQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXRPRFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJd0lpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJeE16Z2lJSGs5SWkwME5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaUxUUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSTJPU0lnZVQwaUxUUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYzJsc2J5SWdlRDBpTkRjaUlIazlJalUxSWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU55a2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMHhNemdpSUhrOUlqTTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNCaGNuUnBZV3hNWldGbVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaU56WWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlOellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXdJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlqRXhOaUlnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXhOVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJakUxTmlJZ0x6NDhMMmMrUEhKbFkzUWdlRDBpTUNJZ2VUMGlNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1DSWdlVDBpTVRRdU5TSWdabTl1ZEMxemFYcGxQU0l4TWlJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKemRHRnlkQ0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1FrVkJUak5EVWxZZ1JHVndiM05wZER3dmRHVjRkRDQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5DUlVGT00wTlNWaUlnZUQwaU1qUXdJaUI1UFNJMElpQXZQanh5WldOMElIZzlJakFpSUhrOUlqTXpNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1qY2lJSGs5SWpNME15SWdabTl1ZEMxemFYcGxQU0l4TUNJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKdGFXUmtiR1VpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBqeDBjM0JoYmo0OFlXNXBiV0YwWlNCaGRIUnlhV0oxZEdWT1lXMWxQU0o0SWlCbWNtOXRQU0l6TnpVaUlIUnZQU0kxTUNJZ1pIVnlQU0l4TUhNaUlISmxjR1ZoZEVOdmRXNTBQU0pwYm1SbFptbHVhWFJsSWlBdlBqQjRZemxqTXpKalpERTJZbVkzWldaaU9EVm1aakUwWlRCak9EWXdNMk5qT1RCbU5tWXlaV1UwT1R3dmRITndZVzQrUEM5MFpYaDBQangwWlhoMElIZzlJakV5TnlJZ2VUMGlNelF6SWlCbWIyNTBMWE5wZW1VOUlqRXdJaUJtYVd4c1BTSlhhR2wwWlNJZ2RHVjRkQzFoYm1Ob2IzSTlJbTFwWkdSc1pTSWdabTl1ZEMxbVlXMXBiSGs5SW1aMWRIVnlZU0krUEhSemNHRnVQanhoYm1sdFlYUmxJR0YwZEhKcFluVjBaVTVoYldVOUluZ2lJR1p5YjIwOUlqVXdJaUIwYnowaUxUSTNOU0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNFl6bGpNekpqWkRFMlltWTNaV1ppT0RWbVpqRTBaVEJqT0RZd00yTmpPVEJtTm1ZeVpXVTBPVHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqSXpOU0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSmxibVFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBsTjBaVzA2SURVeE1qd3ZkR1Y0ZEQ0OEwzTjJaejQ9In0= \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJCRUFOM0NSViJ9LCB7ICJ0cmFpdF90eXBlIjogIlRva2VuIEFkZHJlc3MiLCAidmFsdWUiOiAiMHhjOWMzMmNkMTZiZjdlZmI4NWZmMTRlMGM4NjAzY2M5MGY2ZjJlZTQ5In0sIHsgInRyYWl0X3R5cGUiOiAiSWQiLCAidmFsdWUiOiAiMHhjOWMzMmNkMTZiZjdlZmI4NWZmMTRlMGM4NjAzY2M5MGY2ZjJlZTQ5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMjAwIn0sIHsgInRyYWl0X3R5cGUiOiAic3RlbSIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogNTEyfSwgeyAidHJhaXRfdHlwZSI6ICJpbml0YWwgc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMTAwMDB9LCB7ICJ0cmFpdF90eXBlIjogImdyb3duIHN0YWxrIHBlciBCRFYiLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDM0OTJ9LCB7ICJ0cmFpdF90eXBlIjogInN0YWxrIGdyb3duIHBlciBCRFYgcGVyIHNlYXNvbiIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogNDAwMDAwMCwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQand2Wno0OFp5QnBaRDBpY0dGeWRHbGhiRXhsWVdaUWJHOTBJajQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU53Ykc5MElpQjRQU0l0TXpVaUlIazlJakFpSUhSeVlXNXpabTl5YlQwaWMyTmhiR1VvTVM0MEtTSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JoY25ScFlXeE1aV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmlJK1BIQmhkR2dnWkQwaVRURTNNUzQ0T0RRZ01URTRMams0TTJFMExqa3pNaUEwTGprek1pQXdJREFnTVMweExqQXhPQ0F5TGpZd05pQTBMamN4TlNBMExqY3hOU0F3SURBZ01TMHhMamczT0NBeExqUXpPV010TGpRMk5TNHhPVFV0TVM0M016VXVOekkzTFRJdU16WTBMakUzTmkwdU1qUTJJRE11TWprNExURXVOVGt6SURZdU5URXlMVEl1TWpVeklEY3VPVFUwWVRRdU5UTXlJRFF1TlRNeUlEQWdNQ0F4TFM0ek1UTXRMamt6TTJNdExqSXhNUzB1T1RjMUxTNHdNemd0TVM0M05qTXVNRGM0TFRJdU1qazFMakl3TWkwdU9USXhMak0xTXkweExqWXhNaTQwTmpjdE1pNHhOQzB4TGpFM055NDJPVFF0TWk0Mk5ESXVOVFk1TFRNdU5UVTRMUzR5TnpJdExqYzVOaTB1TnpNeUxURXVNRGd6TFRFdU9USXhMUzQzTkRNdE15NHdNelF1TkRrNExqQXhNU0F4TGprek9TNHhNRGtnTXk0eU5EY2dNUzR4TmpkaE5TNHhNeUExTGpFeklEQWdNQ0F4SURFdU1qRWdNUzQwTVROakxqRTFPUzB1TnpRdU1UazVMUzQ1TlRndU1qTTRMVEV1TVRjNUxqSXdPUzB4TGpJeE15NHpNakl0TVM0NE56SXVNamMwTFRJdU56STBZVGN1TnpNZ055NDNNeUF3SURBZ01DMHVPVEE0TFRNdU1UYzNZeTB1TnpjeUxqUXhOUzB4TGpjNE9TNHhPVFl0TWk0ek56Z3RMak13TkMwdU16TTVMUzR5T0RjdExqVTFOaTB1TmpneUxTNDNOalF0TVM0Mk9USmhNVEl1TnpNNUlERXlMamN6T1NBd0lEQWdNUzB1TVRjMkxUTXVPVEE1WXk0M09Ea3VOakF6SURFdU5EY2dNUzR3TVRrZ01TNDVNemNnTVM0eU9ETXVPVFEwTGpVek5pQXhMak0wTkM0Mk16a2dNUzQzTmpFZ01TNHhOamN1TVRVeUxqRTVNeTQyTkRrdU9EUXlMalU0TmlBeExqYzFNUzB1TURFeExqRTNNaTB1TURVekxqYzVOUzB1TkRZMElERXVNamt6WVRZdU9ETWdOaTQ0TXlBd0lEQWdNU0F4TGpNNE5DQXlMakl5TjJNdU1UUXVNelk0TGpJME1pNDNORFF1TXpFeElERXVNVFV1TVRBM0xTNHlNRGN1TWpZeExTNDBNemt1TlRFeExTNDNNakl1TkRVekxTNDFNVE11T0RjdExqazVNaUF4TGpZd05DMHhMakk0TkM0Mk9ETXRMakkzTWlBeExqSTRMUzR5TkRrZ01TNDNNak10TGpJek5HRTFMak13TWlBMUxqTXdNaUF3SURBZ01TQXhMalE0Tmk0eU56TmFJaTgrUEM5blBqeG5JR2xrUFNKemFXeHZJajQ4Y0dGMGFDQmtQU0pOTlRjdU1UQTRJRGN4TGpJNVl5NHhPRGd0TVRFdU5qVXpMVEV5TGpBeExUSXhMak13TXkweU55NHlORE10TWpFdU5UVXlMVEUxTGpJek5DMHVNalV0TWpjdU56TTJJRGd1T1RrMUxUSTNMamt5TXlBeU1DNDJORGt0TGpFNE55QXhNUzQyTlRRZ01USXVNREVnTWpFdU16QTBJREkzTGpJME5DQXlNUzQxTlRNZ01UVXVNak16TGpJMUlESTNMamN6TlMwNExqazVOU0F5Tnk0NU1qSXRNakF1TmpWYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFM0ME5qUWdNVGt1TlRRMFl5NDJPVGtnTVRZdU5UZzFJREV1TkNBek15NHhOamtnTWk0d09UZ2dORGt1TnpVeUxqQXlNU0F5TGpNNE1TNDBPQ0EwTGpJM09DNDRPRE1nTlM0MU16a3VNamMzTGpnMkxqYzBNU0F5TGpJM05TQXhMamMzT0NBekxqZzJOeTQwT1RRdU56VTVJREV1TWpFeUlERXVOeUF6TGpBd01pQXpMak16TWlBeExqY3pPU0F4TGpVNE5pQXpMak0xSURNdU1EVTJJRFV1TnpNeUlEUXVNems0SURNdU1qa3pJREV1T0RVMUlEWXVNVFV4SURJdU16azJJRGd1TnpreElESXVPRGsySURFdU9EVTFMak0xSURVdU1UUTVMamswT0NBNUxqUTRPQzQxTlRaaE16SXVOekEzSURNeUxqY3dOeUF3SURBZ01DQTVMak14TlMweUxqSTROMk14TGpnMk1pMHVOelU1SURRdU5qUXlMVEV1T1RFM0lEY3VOak16TFRRdU5DQXhMak0wT0MweExqRXlJRE11TkRRNExUSXVPRGszSURVdU1UazNMVFV1T1RWaE1qQXVNVEUwSURJd0xqRXhOQ0F3SURBZ01DQXlMakkxTFRVdU9UazRZeTR5TVMweE55NDFOVEl1TkRJdE16VXVNVEEwTGpZek1pMDFNaTQyTlRkc0xUVTJMamd1T1RVeWFDNHdNREZhSWlCbWFXeHNQU0lqUWpOQ00wSXpJaTgrUEhCaGRHZ2daRDBpVFRVM0xqUTRJREU1TGpRNE1rTTFOeTQyTkRVZ09TNHlOQ0EwTkM0NU56Z3VOekkzSURJNUxqRTROeTQwTmpnZ01UTXVNemszTGpJeExqUTJNeUE0TGpNd015NHlPVGdnTVRndU5UUTJMakV6TkNBeU9DNDNPRGdnTVRJdU9DQXpOeTR6SURJNExqVTVNU0F6Tnk0MU5tTXhOUzQzT1M0eU5UZ2dNamd1TnpJMExUY3VPRE0xSURJNExqZzRPUzB4T0M0d056aGFJaUJtYVd4c1BTSWpRME5ESWk4K1BIQmhkR2dnWkQwaVRUTXdMak14TkNBM0xqRXpOMk11TURBNUxTNDFOakV0TGpZNExURXVNREk0TFRFdU5UTTRMVEV1TURReUxTNDROVGt0TGpBeE5DMHhMalUyTWk0ME15MHhMalUzTVM0NU9URXRMakF4TGpVMk1pNDJPQ0F4TGpBeU9DQXhMalV6T0NBeExqQTBNaTQ0TlRrdU1ERTFJREV1TlRZeUxTNDBNeUF4TGpVM0xTNDVPVm9pSUdacGJHdzlJaU0yTmpZaUx6NDhjR0YwYUNCa1BTSk5OaTQwTVRRZ01qZ3VPRGxoTVRVdU56YzNJREUxTGpjM055QXdJREFnTVMweUxqQTVNeTB5TGpFME5tTXRMamcxTmkweExqQTJNeTB5TGpRMU15MHpMakE1TXkweUxqazNOUzAyTGpFeE1tRXhNUzQzTmpVZ01URXVOelkxSURBZ01DQXhMUzR3T1RNdE15NHpNRGRzTWpVdU5ETXRPUzQ1TnpaakxqQTBNeTR4TkRJdU1UZzRMalUxTlM0Mk1EUXVPRFk0TGpRMkxqTTBOaTQ1TkRjdU16UWdNUzR3T0RZdU16TTBURFl1TkRFeklESTRMamc0T0hZdU1EQXlXaUlnWm1sc2JEMGlJMFUyUlRaRk5pSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNHpNeUlnWkQwaVRURXVORGMzSURFMkxqQXlPV011TWpVdExqa3pNUzQzTURZdE1pNHlOVGdnTVM0MU55MHpMalk1TlM0Mk5UVXRNUzR3T1RJZ01TNHlPVEl0TVM0NE1qVWdNUzQzTmkweUxqTTFPQzQxT0RRdExqWTJOU0F4TGpjM05pMHhMamt6TkNBekxqWTNPUzB6TGpJNUlESXVPVFV6TFRJdU1UQTFJRFV1TmprMkxUTXVNRFVnTnk0M01qTXRNeTQzTTJFek55NHpOU0F6Tnk0ek5TQXdJREFnTVNBMkxqUTROUzB4TGpVME4ydzFMakkwTWlBMExqTXhObUV4TGpRNElERXVORGdnTUNBd0lEQXRNUzR5TVRRdU9UWTNUREV1TkRnZ01UWXVNRE5vTFM0d01ESmFJaUJtYVd4c1BTSWpPVGs1SWk4K1BIQmhkR2dnYjNCaFkybDBlVDBpTGpRMElpQmtQU0pOTVM0NE1TQXlOaTQxTXpKakxqSXdOaTQwT1RRdU5EZzBJREV1TURVdU9EWWdNUzQyTTJFeE1DNHlOallnTVRBdU1qWTJJREFnTUNBd0lESXVNamM0SURJdU5EZzJURFl1TlRVeUlEYzRMakl5WVRFM0xqSTNNaUF4Tnk0eU56SWdNQ0F3SURFdE15MDNMalF4TTB3eExqZ3hJREkyTGpVek1sb2lJR1pwYkd3OUlpTkZOa1UyUlRZaUx6NDhjR0YwYUNCa1BTSnRNek11TURreUlEUTVMalEwTVMwMkxqTTRNU0F4TlM0eU1URnpMVFl1TURjNExURXhMakUxT1NBMkxqTTRNUzB4TlM0eU1Wb2lJR1pwYkd3OUlpTTRSVGhGT0VVaUx6NDhjR0YwYUNCa1BTSnRNall1TnpJMUlEWTBMamcxT0MwdU1Ea3hMUzR4TnpWakxTNHdNall0TGpBME9TMHlMall6TkMwMExqa3lNeTB1T0RZM0xUa3VNemNnTVM0d05UY3RNaTQzTVRjZ015NDFNVGd0TkM0M01qVWdOeTR6TFRVdU9UUTJiQzR4T0RjdExqQTJNUzAyTGpVeklERTFMalUxTWxwdE5pNHlNVEl0TVRVdU1qWTRZeTB6TGpZeU1TQXhMakl4TnkwMUxqazVNU0F6TGpFMk9DMDNMakF5TWlBMUxqYzVPQzB4TGpVek9DQXpMamt3T0M0ek5UVWdPQzR4TmpZdU56ZzRJRGt1TURVMGJEWXVNak0wTFRFMExqZzFNbHBOTWpndU1Ea3pJRFl6TGpjek4ydzBMalE0TkMweE1DNDROM00zTGpNMk5TQTJMak16TnkwMExqUTROQ0F4TUM0NE4xb2lJR1pwYkd3OUlpTTRSVGhGT0VVaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNME5rSTVOVFVpTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGpORFVsWWlQanh5WldOMElIazlJaTQxSWlCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU56WTBMVE11TlRBMElEa3VNelpUTGpJNU9DQTBMalE1T1NBM0xqWTROeUF4TGpjMk5Wb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNHhNeklnT0M0d056aGpMUzQwTmpZdU5qUXRNUzR5T1RjZ01TNHpNak10TWk0Mk9UVWdNUzQ1T1RKc01pNHhNall0TlM0M056ZGpMakE0T1M0d09TNHhPVE11TWpBMExqTXVNek00TGpNd015NHpOelV1TmpJMUxqZzVNUzQzTkRRZ01TNDBPRFF1TVRFM0xqVTRNeTR3TkNBeExqSTFNeTB1TkRjMUlERXVPVFl6V2lJZ1ptbHNiRDBpZFhKc0tDTmhLU0lnYzNSeWIydGxQU0lqWm1abUlpQnpkSEp2YTJVdGQybGtkR2c5SWk0MUlpOCtQR1JsWm5NK1BHeHBibVZoY2tkeVlXUnBaVzUwSUdsa1BTSmhJaUI0TVQwaU5pNDVOU0lnZVRFOUlqTXVPRFV6SWlCNE1qMGlOaTQ1TlNJZ2VUSTlJakV3TGpVME5DSWdaM0poWkdsbGJuUlZibWwwY3owaWRYTmxjbE53WVdObFQyNVZjMlVpUGp4emRHOXdJSE4wYjNBdFkyOXNiM0k5SWlNNE1qQXlNRElpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJaTR4T0RJaUlITjBiM0F0WTI5c2IzSTlJaU5HTnpGRk1EVWlMejQ4YzNSdmNDQnZabVp6WlhROUlpNDFNVFlpSUhOMGIzQXRZMjlzYjNJOUlpTkdNRVkxTURjaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWk0M016UWlJSE4wYjNBdFkyOXNiM0k5SWlNNE5VTkVOelVpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJakVpSUhOMGIzQXRZMjlzYjNJOUlpTXdNamxFUmtJaUx6NDhMMnhwYm1WaGNrZHlZV1JwWlc1MFBqd3ZaR1ZtY3o0OEwyYytQR2NnYVdROUluVnlRa1ZCVGlJK1BISmxZM1FnZDJsa2RHZzlJakV5SWlCb1pXbG5hSFE5SWpFeUlpQnllRDBpTmlJZ1ptbHNiRDBpSXpkR05UVXpNeUl2UGp4d1lYUm9JR1E5SW0wM0xqWTROeUF4TGpJMk5TMHpMalV3TkNBNUxqTTJVeTR5T1RnZ015NDVPVGtnTnk0Mk9EY2dNUzR5TmpaYWJTMHlMalk1TVNBNExqYzRJREl1TkRZeUxUWXVOamt4Y3pRdU5UTTRJRE11TmpjdE1pNDBOaklnTmk0Mk9URmFJaUJtYVd4c1BTSWpabVptSWk4K1BDOW5QanhuSUdsa1BTSkNSVUZPUlZSSUlqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamcwSURFdU1qWTFMVE11TlRBMUlEa3VNelpqTGpBd015QXdMVE11T0RnMExUWXVOakkxSURNdU5UQTFMVGt1TXpaYUlpQm1hV3hzUFNJalptWm1JaTgrUEhCaGRHZ2daRDBpVFRndU9UVXlJRFl1T1RnMllTNHdOak11TURZeklEQWdNQ0F4TFM0d01qSXVNREF6WXkwdU56RXVNVE10TVM0ME1qUXVNalUxTFRJdU1UTTBMak00TVMwdU1qZ3hMakExTWkwdU5UWTFMakV3TXkwdU9EUTJMakUxTW1FdU1ETTJMakF6TmlBd0lEQWdNUzB1TURJMklEQnNNaTR4TkMwMUxqWXlOUzR3TURRdExqQXdNMk11TWprM0lERXVOekF5TGpVNUlETXVNemswTGpnNE5DQTFMakE1TWxwdExTNHhPRGN1TkRjNFl5MHhMakkyTmk0NE5Ua3RNaTQxTXpFZ01TNDNNakV0TXk0NElESXVOVGhzTGpjNE1TMHlMakExTkdNdU1EQTNMakF3TkM0d01UTWdNQ0F1TURJeklEQWdMamMxT1MwdU1UTXlJREV1TlRFMExTNHlOamdnTWk0eU55MHVOR3d1TmprM0xTNHhNall1TURNdExqQXdObU10TGpBd05DNHdNRE1nTUNBdU1EQTJJREFnTGpBd05sb2lJR1pwYkd3OUlpTXdNREFpTHo0OEwyYytQR2NnYVdROUluVnlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6ZEdOVFV6TXlJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSnNaV0ZtVW05M0lqNDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXdJaUI1UFNJd0lpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlMVEV5SWlCNVBTSXROeUl2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweU5DSWdlVDBpTFRFMElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlMVE0ySWlCNVBTSXRNakVpTHo0OEwyYytQQzlrWldaelBqeHlaV04wSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU16VXdJaUJ5ZUQwaU1UQWlJR1pwYkd3OUlpTXlOVE16TWpZaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnphV3h2SWlCNFBTSTVPU0lnZVQwaU5UVWlMejQ4WnlCcFpEMGlZV3hzVUd4dmRDSWdZMnhwY0Mxd1lYUm9QU0oxY213b0kySnZjbVJsY2sxaGMyc3BJajQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaUxURTJOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXRNVFkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTUNJZ2VUMGlMVEV5TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpFek9DSWdlVDBpTFRFeU5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMHhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTA0TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXdJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMDBOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTAyT1NJZ2VUMGlMVFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamMybHNieUlnZUQwaU5EY2lJSGs5SWpVMUlpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOeWtpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTB4TXpnaUlIazlJak0ySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQmhjblJwWVd4TVpXRm1VR3h2ZENJZ2VEMGlNVE00SWlCNVBTSXpOaUlnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTAyT1NJZ2VUMGlOellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJMk9TSWdlVDBpTnpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l3SWlCNVBTSXhNVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l4TXpnaUlIazlJakV4TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l4TlRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpFMU5pSWdMejQ4TDJjK1BISmxZM1FnZUQwaU1DSWdlVDBpTUNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXlNQ0lnY25nOUlqVWlJR1pwYkd3OUlpTXlOREkwTWpRaUx6NDhkR1Y0ZENCNFBTSXhNQ0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSnpkR0Z5ZENJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStRa1ZCVGpORFVsWWdSR1Z3YjNOcGREd3ZkR1Y0ZEQ0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOQ1JVRk9NME5TVmlJZ2VEMGlNalF3SWlCNVBTSTBJaUF2UGp4eVpXTjBJSGc5SWpBaUlIazlJak16TUNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXlNQ0lnY25nOUlqVWlJR1pwYkd3OUlpTXlOREkwTWpRaUx6NDhkR1Y0ZENCNFBTSXhNamNpSUhrOUlqTTBNeUlnWm05dWRDMXphWHBsUFNJeE1DSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSnRhV1JrYkdVaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQangwYzNCaGJqNDhZVzVwYldGMFpTQmhkSFJ5YVdKMWRHVk9ZVzFsUFNKNElpQm1jbTl0UFNJek56VWlJSFJ2UFNJMU1DSWdaSFZ5UFNJeE1ITWlJSEpsY0dWaGRFTnZkVzUwUFNKcGJtUmxabWx1YVhSbElpQXZQakI0WXpsak16SmpaREUyWW1ZM1pXWmlPRFZtWmpFMFpUQmpPRFl3TTJOak9UQm1ObVl5WldVME9Ud3ZkSE53WVc0K1BDOTBaWGgwUGp4MFpYaDBJSGc5SWpFeU55SWdlVDBpTXpReklpQm1iMjUwTFhOcGVtVTlJakV3SWlCbWFXeHNQU0pYYUdsMFpTSWdkR1Y0ZEMxaGJtTm9iM0k5SW0xcFpHUnNaU0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1BIUnpjR0Z1UGp4aGJtbHRZWFJsSUdGMGRISnBZblYwWlU1aGJXVTlJbmdpSUdaeWIyMDlJalV3SWlCMGJ6MGlMVEkzTlNJZ1pIVnlQU0l4TUhNaUlISmxjR1ZoZEVOdmRXNTBQU0pwYm1SbFptbHVhWFJsSWlBdlBqQjRZemxqTXpKalpERTJZbVkzWldaaU9EVm1aakUwWlRCak9EWXdNMk5qT1RCbU5tWXlaV1UwT1R3dmRITndZVzQrUEM5MFpYaDBQangwWlhoMElIZzlJakl6TlNJZ2VUMGlNVFF1TlNJZ1ptOXVkQzF6YVhwbFBTSXhNaUlnWm1sc2JEMGlWMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0psYm1RaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQbE4wWlcwNklEVXhNand2ZEdWNGRENDhMM04yWno0PSJ9 \ No newline at end of file diff --git a/protocol/test/data/base64EncodedImageBeanEth.txt b/protocol/test/data/base64EncodedImageBeanEth.txt index ca01c52418..c1a46d1a4e 100644 --- a/protocol/test/data/base64EncodedImageBeanEth.txt +++ b/protocol/test/data/base64EncodedImageBeanEth.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IEJFQU5FVEhcblRva2VuIEFkZHJlc3M6IDB4YmVhMGUxMTI4MmUyYmI1ODkzYmVjZTExMGNmMTk5NTAxZTg3MmJhZFxuSWQ6IDB4YmVhMGUxMTI4MmUyYmI1ODkzYmVjZTExMGNmMTk5NTAxZTg3MmJhZGZmZmZmZmZmZmZmZmYwMDAwMDAwMDAwMlxuc3RlbTogLTE3NTkyMTg2MDQ0NDE0XG5pbml0YWwgc3RhbGsgcGVyIEJEVjogMTAwMDBcbmdyb3duIHN0YWxrIHBlciBCRFY6IDE3NTkyMTg2MDQ4NDE4XG5zdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb246IDQwMDAwMDBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCamJHRnpjejBpYzNablFtOWtlU0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJek5UQWlJSFpwWlhkQ2IzZzlJakFnTUNBeU5UVWdNelV3SWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhodGJHNXpPbmhzYVc1clBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJajQ4WkdWbWN6NDhaeUJwWkQwaWNHeHZkQ0krUEhCaGRHZ2daRDBpVFRjNUxqVTNNamdnTVRJNUxqSTJOVXd4TWpjdU5EWTVJREUxTmk0NE16Tk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UQXhMalk1TjB3M09TNDFOekk0SURFeU9TNHlOalZhSWlCbWFXeHNQU0lqT1RRMFFUSTNJaTgrUEhCaGRHZ2daRDBpVFRjNUxqVXpNeklnTVRNekxqUXlOa3czT1M0MU56STNJREV5T1M0eU5qVk1NVEkzTGpRMk9TQXhOVFl1T0RNelRERXlOeTQxTURjZ01UWXdMamt3T0V3M09TNDFNek15SURFek15NDBNalphSWlCbWFXeHNQU0lqTnpVek9URkdJaTgrUEhCaGRHZ2daRDBpVFRFM05TNDBOamNnTVRNekxqUk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UVTJMamd6TTB3eE1qY3VOVEEzSURFMk1DNDVNRGhNTVRjMUxqUTJOeUF4TXpNdU5Gb2lJR1pwYkd3OUlpTTJOek16TVVVaUx6NDhMMmMrUEdjZ2FXUTlJbVoxYkd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUWXdJaUI1UFNJeE5DSWdabWxzYkQwaUkwRTRRemd6UVNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUY3pJaUI1UFNJeU1TSWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKbGJYQjBlVkJzYjNRaVBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQnNiM1FpSUhnOUlpMHpOU0lnZVQwaU1DSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSndZWEowYVdGc1RHVmhabEp2ZHlJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaU1DSWdlVDBpTUNJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1lpSUhnOUlpMHhNaUlnZVQwaUxUY2lMejQ4TDJjK1BHY2dhV1E5SW5CaGNuUnBZV3hNWldGbVVHeHZkQ0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0d4dmRDSWdlRDBpTFRNMUlpQjVQU0l3SWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU53WVhKMGFXRnNUR1ZoWmxKdmR5SWdlRDBpTFRNMUlpQjVQU0l3SWlCbWFXeHNQU0lqUVRoRE9ETkJJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhMMmMrUEdjZ2FXUTlJbXhsWVdZaVBqeHdZWFJvSUdROUlrMHhOekV1T0RnMElERXhPQzQ1T0ROaE5DNDVNeklnTkM0NU16SWdNQ0F3SURFdE1TNHdNVGdnTWk0Mk1EWWdOQzQzTVRVZ05DNDNNVFVnTUNBd0lERXRNUzQ0TnpnZ01TNDBNemxqTFM0ME5qVXVNVGsxTFRFdU56TTFMamN5TnkweUxqTTJOQzR4TnpZdExqSTBOaUF6TGpJNU9DMHhMalU1TXlBMkxqVXhNaTB5TGpJMU15QTNMamsxTkdFMExqVXpNaUEwTGpVek1pQXdJREFnTVMwdU16RXpMUzQ1TXpOakxTNHlNVEV0TGprM05TMHVNRE00TFRFdU56WXpMakEzT0MweUxqSTVOUzR5TURJdExqa3lNUzR6TlRNdE1TNDJNVEl1TkRZM0xUSXVNVFF0TVM0eE56Y3VOamswTFRJdU5qUXlMalUyT1MwekxqVTFPQzB1TWpjeUxTNDNPVFl0TGpjek1pMHhMakE0TXkweExqa3lNUzB1TnpRekxUTXVNRE0wTGpRNU9DNHdNVEVnTVM0NU16a3VNVEE1SURNdU1qUTNJREV1TVRZM1lUVXVNVE1nTlM0eE15QXdJREFnTVNBeExqSXhJREV1TkRFell5NHhOVGt0TGpjMExqRTVPUzB1T1RVNExqSXpPQzB4TGpFM09TNHlNRGt0TVM0eU1UTXVNekl5TFRFdU9EY3lMakkzTkMweUxqY3lOR0UzTGpjeklEY3VOek1nTUNBd0lEQXRMamt3T0MwekxqRTNOMk10TGpjM01pNDBNVFV0TVM0M09Ea3VNVGsyTFRJdU16YzRMUzR6TURRdExqTXpPUzB1TWpnM0xTNDFOVFl0TGpZNE1pMHVOelkwTFRFdU5qa3lZVEV5TGpjek9TQXhNaTQzTXprZ01DQXdJREV0TGpFM05pMHpMamt3T1dNdU56ZzVMall3TXlBeExqUTNJREV1TURFNUlERXVPVE0zSURFdU1qZ3pMamswTkM0MU16WWdNUzR6TkRRdU5qTTVJREV1TnpZeElERXVNVFkzTGpFMU1pNHhPVE11TmpRNUxqZzBNaTQxT0RZZ01TNDNOVEV0TGpBeE1TNHhOekl0TGpBMU15NDNPVFV0TGpRMk5DQXhMakk1TTJFMkxqZ3pJRFl1T0RNZ01DQXdJREVnTVM0ek9EUWdNaTR5TWpkakxqRTBMak0yT0M0eU5ESXVOelEwTGpNeE1TQXhMakUxTGpFd055MHVNakEzTGpJMk1TMHVORE01TGpVeE1TMHVOekl5TGpRMU15MHVOVEV6TGpnM0xTNDVPVElnTVM0Mk1EUXRNUzR5T0RRdU5qZ3pMUzR5TnpJZ01TNHlPQzB1TWpRNUlERXVOekl6TFM0eU16UmhOUzR6TURJZ05TNHpNRElnTUNBd0lERWdNUzQwT0RZdU1qY3pXaUl2UGp3dlp6NDhaeUJwWkQwaWMybHNieUkrUEhCaGRHZ2daRDBpVFRVM0xqRXdPQ0EzTVM0eU9XTXVNVGc0TFRFeExqWTFNeTB4TWk0d01TMHlNUzR6TURNdE1qY3VNalF6TFRJeExqVTFNaTB4TlM0eU16UXRMakkxTFRJM0xqY3pOaUE0TGprNU5TMHlOeTQ1TWpNZ01qQXVOalE1TFM0eE9EY2dNVEV1TmpVMElERXlMakF4SURJeExqTXdOQ0F5Tnk0eU5EUWdNakV1TlRVeklERTFMakl6TXk0eU5TQXlOeTQzTXpVdE9DNDVPVFVnTWpjdU9USXlMVEl3TGpZMVdpSWdabWxzYkQwaUl6WTJOaUl2UGp4d1lYUm9JR1E5SWswdU5EWTBJREU1TGpVME5HTXVOams1SURFMkxqVTROU0F4TGpRZ016TXVNVFk1SURJdU1EazRJRFE1TGpjMU1pNHdNakVnTWk0ek9ERXVORGdnTkM0eU56Z3VPRGd6SURVdU5UTTVMakkzTnk0NE5pNDNOREVnTWk0eU56VWdNUzQzTnpnZ015NDROamN1TkRrMExqYzFPU0F4TGpJeE1pQXhMamNnTXk0d01ESWdNeTR6TXpJZ01TNDNNemtnTVM0MU9EWWdNeTR6TlNBekxqQTFOaUExTGpjek1pQTBMak01T0NBekxqSTVNeUF4TGpnMU5TQTJMakUxTVNBeUxqTTVOaUE0TGpjNU1TQXlMamc1TmlBeExqZzFOUzR6TlNBMUxqRTBPUzQ1TkRnZ09TNDBPRGd1TlRVMllUTXlMamN3TnlBek1pNDNNRGNnTUNBd0lEQWdPUzR6TVRVdE1pNHlPRGRqTVM0NE5qSXRMamMxT1NBMExqWTBNaTB4TGpreE55QTNMall6TXkwMExqUWdNUzR6TkRndE1TNHhNaUF6TGpRME9DMHlMamc1TnlBMUxqRTVOeTAxTGprMVlUSXdMakV4TkNBeU1DNHhNVFFnTUNBd0lEQWdNaTR5TlMwMUxqazVPR011TWpFdE1UY3VOVFV5TGpReUxUTTFMakV3TkM0Mk16SXROVEl1TmpVM2JDMDFOaTQ0TGprMU1tZ3VNREF4V2lJZ1ptbHNiRDBpSTBJelFqTkNNeUl2UGp4d1lYUm9JR1E5SWswMU55NDBPQ0F4T1M0ME9ESkROVGN1TmpRMUlEa3VNalFnTkRRdU9UYzRMamN5TnlBeU9TNHhPRGN1TkRZNElERXpMak01Tnk0eU1TNDBOak1nT0M0ek1ETXVNams0SURFNExqVTBOaTR4TXpRZ01qZ3VOemc0SURFeUxqZ2dNemN1TXlBeU9DNDFPVEVnTXpjdU5UWmpNVFV1TnprdU1qVTRJREk0TGpjeU5DMDNMamd6TlNBeU9DNDRPRGt0TVRndU1EYzRXaUlnWm1sc2JEMGlJME5EUXlJdlBqeHdZWFJvSUdROUlrMHpNQzR6TVRRZ055NHhNemRqTGpBd09TMHVOVFl4TFM0Mk9DMHhMakF5T0MweExqVXpPQzB4TGpBME1pMHVPRFU1TFM0d01UUXRNUzQxTmpJdU5ETXRNUzQxTnpFdU9Ua3hMUzR3TVM0MU5qSXVOamdnTVM0d01qZ2dNUzQxTXpnZ01TNHdOREl1T0RVNUxqQXhOU0F4TGpVMk1pMHVORE1nTVM0MU55MHVPVGxhSWlCbWFXeHNQU0lqTmpZMklpOCtQSEJoZEdnZ1pEMGlUVFl1TkRFMElESTRMamc1WVRFMUxqYzNOeUF4TlM0M056Y2dNQ0F3SURFdE1pNHdPVE10TWk0eE5EWmpMUzQ0TlRZdE1TNHdOak10TWk0ME5UTXRNeTR3T1RNdE1pNDVOelV0Tmk0eE1USmhNVEV1TnpZMUlERXhMamMyTlNBd0lEQWdNUzB1TURrekxUTXVNekEzYkRJMUxqUXpMVGt1T1RjMll5NHdORE11TVRReUxqRTRPQzQxTlRVdU5qQTBMamcyT0M0ME5pNHpORFl1T1RRM0xqTTBJREV1TURnMkxqTXpORXcyTGpReE15QXlPQzQ0T0RoMkxqQXdNbG9pSUdacGJHdzlJaU5GTmtVMlJUWWlMejQ4Y0dGMGFDQnZjR0ZqYVhSNVBTSXVNek1pSUdROUlrMHhMalEzTnlBeE5pNHdNamxqTGpJMUxTNDVNekV1TnpBMkxUSXVNalU0SURFdU5UY3RNeTQyT1RVdU5qVTFMVEV1TURreUlERXVNamt5TFRFdU9ESTFJREV1TnpZdE1pNHpOVGd1TlRnMExTNDJOalVnTVM0M056WXRNUzQ1TXpRZ015NDJOemt0TXk0eU9TQXlMamsxTXkweUxqRXdOU0ExTGpZNU5pMHpMakExSURjdU56SXpMVE11TnpOaE16Y3VNelVnTXpjdU16VWdNQ0F3SURFZ05pNDBPRFV0TVM0MU5EZHNOUzR5TkRJZ05DNHpNVFpoTVM0ME9DQXhMalE0SURBZ01DQXdMVEV1TWpFMExqazJOMHd4TGpRNElERTJMakF6YUMwdU1EQXlXaUlnWm1sc2JEMGlJems1T1NJdlBqeHdZWFJvSUc5d1lXTnBkSGs5SWk0ME5DSWdaRDBpVFRFdU9ERWdNall1TlRNeVl5NHlNRFl1TkRrMExqUTROQ0F4TGpBMUxqZzJJREV1TmpOaE1UQXVNalkySURFd0xqSTJOaUF3SURBZ01DQXlMakkzT0NBeUxqUTROa3cyTGpVMU1pQTNPQzR5TW1FeE55NHlOeklnTVRjdU1qY3lJREFnTUNBeExUTXROeTQwTVROTU1TNDRNU0F5Tmk0MU16SmFJaUJtYVd4c1BTSWpSVFpGTmtVMklpOCtQSEJoZEdnZ1pEMGliVE16TGpBNU1pQTBPUzQwTkRFdE5pNHpPREVnTVRVdU1qRXhjeTAyTGpBM09DMHhNUzR4TlRrZ05pNHpPREV0TVRVdU1qRmFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQSEJoZEdnZ1pEMGliVEkyTGpjeU5TQTJOQzQ0TlRndExqQTVNUzB1TVRjMVl5MHVNREkyTFM0d05Ea3RNaTQyTXpRdE5DNDVNak10TGpnMk55MDVMak0zSURFdU1EVTNMVEl1TnpFM0lETXVOVEU0TFRRdU56STFJRGN1TXkwMUxqazBObXd1TVRnM0xTNHdOakV0Tmk0MU15QXhOUzQxTlRKYWJUWXVNakV5TFRFMUxqSTJPR010TXk0Mk1qRWdNUzR5TVRjdE5TNDVPVEVnTXk0eE5qZ3ROeTR3TWpJZ05TNDNPVGd0TVM0MU16Z2dNeTQ1TURndU16VTFJRGd1TVRZMkxqYzRPQ0E1TGpBMU5HdzJMakl6TkMweE5DNDROVEphVFRJNExqQTVNeUEyTXk0M016ZHNOQzQwT0RRdE1UQXVPRGR6Tnk0ek5qVWdOaTR6TXpjdE5DNDBPRFFnTVRBdU9EZGFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQQzluUGp4bklHbGtQU0pDUlVGT0lqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU1qWTFMVE11TlRBMElEa3VNelpUTGpJNU9DQXpMams1T1NBM0xqWTROeUF4TGpJMk5scHRMVEl1TmpreElEZ3VOemdnTWk0ME5qSXROaTQyT1RGek5DNDFNemdnTXk0Mk55MHlMalEyTWlBMkxqWTVNVm9pSUdacGJHdzlJaU5tWm1ZaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0elExSldJajQ4Y21WamRDQjVQU0l1TlNJZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TnlBeExqYzJOQzB6TGpVd05DQTVMak0yVXk0eU9UZ2dOQzQwT1RrZ055NDJPRGNnTVM0M05qVmFJaUJtYVd4c1BTSWpabVptSWk4K1BIQmhkR2dnWkQwaVRUZ3VNVE15SURndU1EYzRZeTB1TkRZMkxqWTBMVEV1TWprM0lERXVNekl6TFRJdU5qazFJREV1T1RreWJESXVNVEkyTFRVdU56YzNZeTR3T0RrdU1Ea3VNVGt6TGpJd05DNHpMak16T0M0ek1ETXVNemMxTGpZeU5TNDRPVEV1TnpRMElERXVORGcwTGpFeE55NDFPRE11TURRZ01TNHlOVE10TGpRM05TQXhMamsyTTFvaUlHWnBiR3c5SW5WeWJDZ2pZU2tpSUhOMGNtOXJaVDBpSTJabVppSWdjM1J5YjJ0bExYZHBaSFJvUFNJdU5TSXZQanhrWldaelBqeHNhVzVsWVhKSGNtRmthV1Z1ZENCcFpEMGlZU0lnZURFOUlqWXVPVFVpSUhreFBTSXpMamcxTXlJZ2VESTlJall1T1RVaUlIa3lQU0l4TUM0MU5EUWlJR2R5WVdScFpXNTBWVzVwZEhNOUluVnpaWEpUY0dGalpVOXVWWE5sSWo0OGMzUnZjQ0J6ZEc5d0xXTnZiRzl5UFNJak9ESXdNakF5SWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TVRneUlpQnpkRzl3TFdOdmJHOXlQU0lqUmpjeFJUQTFJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOVEUySWlCemRHOXdMV052Ykc5eVBTSWpSakJHTlRBM0lpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU56TTBJaUJ6ZEc5d0xXTnZiRzl5UFNJak9EVkRSRGMxSWk4K1BITjBiM0FnYjJabWMyVjBQU0l4SWlCemRHOXdMV052Ykc5eVBTSWpNREk1UkVaQ0lpOCtQQzlzYVc1bFlYSkhjbUZrYVdWdWRENDhMMlJsWm5NK1BDOW5QanhuSUdsa1BTSjFja0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNM1JqVTFNek1pTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSjFja0pGUVU1RlZFZ2lQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RRZ01TNHlOalV0TXk0MU1EVWdPUzR6Tm1NdU1EQXpJREF0TXk0NE9EUXROaTQyTWpVZ015NDFNRFV0T1M0ek5sb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNDVOVElnTmk0NU9EWmhMakEyTXk0d05qTWdNQ0F3SURFdExqQXlNaTR3TUROakxTNDNNUzR4TXkweExqUXlOQzR5TlRVdE1pNHhNelF1TXpneExTNHlPREV1TURVeUxTNDFOalV1TVRBekxTNDRORFl1TVRVeVlTNHdNell1TURNMklEQWdNQ0F4TFM0d01qWWdNR3d5TGpFMExUVXVOakkxTGpBd05DMHVNREF6WXk0eU9UY2dNUzQzTURJdU5Ua2dNeTR6T1RRdU9EZzBJRFV1TURreVdtMHRMakU0Tnk0ME56aGpMVEV1TWpZMkxqZzFPUzB5TGpVek1TQXhMamN5TVMwekxqZ2dNaTQxT0d3dU56Z3hMVEl1TURVMFl5NHdNRGN1TURBMExqQXhNeUF3SUM0d01qTWdNQ0F1TnpVNUxTNHhNeklnTVM0MU1UUXRMakkyT0NBeUxqSTNMUzQwYkM0Mk9UY3RMakV5Tmk0d015MHVNREEyWXkwdU1EQTBMakF3TXlBd0lDNHdNRFlnTUNBdU1EQTJXaUlnWm1sc2JEMGlJekF3TUNJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1JaUI0UFNJdE1qUWlJSGs5SWkweE5DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB6TmlJZ2VUMGlMVEl4SWk4K1BDOW5Qand2WkdWbWN6NDhjbVZqZENCM2FXUjBhRDBpTWpVMUlpQm9aV2xuYUhROUlqTTFNQ0lnY25nOUlqRXdJaUJtYVd4c1BTSWpNalV6TXpJMklpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjMmxzYnlJZ2VEMGlPVGtpSUhrOUlqVTFJaTgrUEdjZ2FXUTlJbUZzYkZCc2IzUWlJR05zYVhBdGNHRjBhRDBpZFhKc0tDTmliM0prWlhKTllYTnJLU0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l0TmpraUlIazlJaTB4TmpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSTJPU0lnZVQwaUxURTJOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObWRXeHNUR1ZoWmxCc2IzUWlJSGc5SWpBaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJdE1USTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSTJPU0lnZVQwaUxUZzBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTFRFek9DSWdlVDBpTFRRMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlNQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTVRNNElpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXROamtpSUhrOUlpMDBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzTnBiRzhpSUhnOUlqUTNJaUI1UFNJMU5TSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMamNwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5tZFd4c1RHVmhabEJzYjNRaUlIZzlJakV6T0NJZ2VUMGlNellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlOamtpSUhrOUlqYzJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTFRFek9DSWdlVDBpTVRFMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlNQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSTJPU0lnZVQwaU1UVTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l4TlRZaUlDOCtQQzluUGp4eVpXTjBJSGc5SWpBaUlIazlJakFpSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU1qQWlJSEo0UFNJMUlpQm1hV3hzUFNJak1qUXlOREkwSWk4K1BIUmxlSFFnZUQwaU1UQWlJSGs5SWpFMExqVWlJR1p2Ym5RdGMybDZaVDBpTVRJaUlHWnBiR3c5SWxkb2FYUmxJaUIwWlhoMExXRnVZMmh2Y2owaWMzUmhjblFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBrSkZRVTVGVkVnZ1JHVndiM05wZER3dmRHVjRkRDQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5DUlVGT1JWUklJaUI0UFNJeU5EQWlJSGs5SWpRaUlDOCtQSEpsWTNRZ2VEMGlNQ0lnZVQwaU16TXdJaUIzYVdSMGFEMGlNalUxSWlCb1pXbG5hSFE5SWpJd0lpQnllRDBpTlNJZ1ptbHNiRDBpSXpJME1qUXlOQ0l2UGp4MFpYaDBJSGc5SWpFeU55SWdlVDBpTXpReklpQm1iMjUwTFhOcGVtVTlJakV3SWlCbWFXeHNQU0pYYUdsMFpTSWdkR1Y0ZEMxaGJtTm9iM0k5SW0xcFpHUnNaU0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1BIUnpjR0Z1UGp4aGJtbHRZWFJsSUdGMGRISnBZblYwWlU1aGJXVTlJbmdpSUdaeWIyMDlJak0zTlNJZ2RHODlJalV3SWlCa2RYSTlJakV3Y3lJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUM4K01IaGlaV0V3WlRFeE1qZ3laVEppWWpVNE9UTmlaV05sTVRFd1kyWXhPVGsxTURGbE9EY3lZbUZrUEM5MGMzQmhiajQ4TDNSbGVIUStQSFJsZUhRZ2VEMGlNVEkzSWlCNVBTSXpORE1pSUdadmJuUXRjMmw2WlQwaU1UQWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGliV2xrWkd4bElpQm1iMjUwTFdaaGJXbHNlVDBpWm5WMGRYSmhJajQ4ZEhOd1lXNCtQR0Z1YVcxaGRHVWdZWFIwY21saWRYUmxUbUZ0WlQwaWVDSWdabkp2YlQwaU5UQWlJSFJ2UFNJdE1qYzFJaUJrZFhJOUlqRXdjeUlnY21Wd1pXRjBRMjkxYm5ROUltbHVaR1ZtYVc1cGRHVWlJQzgrTUhoaVpXRXdaVEV4TWpneVpUSmlZalU0T1ROaVpXTmxNVEV3WTJZeE9UazFNREZsT0RjeVltRmtQQzkwYzNCaGJqNDhMM1JsZUhRK1BIUmxlSFFnZUQwaU1qTTFJaUI1UFNJeE5DNDFJaUJtYjI1MExYTnBlbVU5SWpFeUlpQm1hV3hzUFNKWGFHbDBaU0lnZEdWNGRDMWhibU5vYjNJOUltVnVaQ0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1UzUmxiVG9nTFRFdU56VTVNakZsTVRNOEwzUmxlSFErUEM5emRtYysifQ== \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJCRUFORVRIIn0sIHsgInRyYWl0X3R5cGUiOiAiVG9rZW4gQWRkcmVzcyIsICJ2YWx1ZSI6ICIweGJlYTBlMTEyODJlMmJiNTg5M2JlY2UxMTBjZjE5OTUwMWU4NzJiYWQifSwgeyAidHJhaXRfdHlwZSI6ICJJZCIsICJ2YWx1ZSI6ICIweGJlYTBlMTEyODJlMmJiNTg5M2JlY2UxMTBjZjE5OTUwMWU4NzJiYWRmZmZmZmZmZmZmZmZmMDAwMDAwMDAwMDIifSwgeyAidHJhaXRfdHlwZSI6ICJzdGVtIiwgImRpc3BsYXlfdHlwZSI6ICJudW1iZXIiLCAidmFsdWUiOiAtMTc1OTIxODYwNDQ0MTR9LCB7ICJ0cmFpdF90eXBlIjogImluaXRhbCBzdGFsayBwZXIgQkRWIiwgImRpc3BsYXlfdHlwZSI6ICJudW1iZXIiLCAidmFsdWUiOiAxMDAwMH0sIHsgInRyYWl0X3R5cGUiOiAiZ3Jvd24gc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMTc1OTIxODYwNDg0MTh9LCB7ICJ0cmFpdF90eXBlIjogInN0YWxrIGdyb3duIHBlciBCRFYgcGVyIHNlYXNvbiIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogNDAwMDAwMCwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OEwyYytQR2NnYVdROUluQmhjblJwWVd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOd1lYSjBhV0ZzVEdWaFpsSnZkeUlnZUQwaUxUTTFJaUI1UFNJd0lpQm1hV3hzUFNJalFUaERPRE5CSWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4TDJjK1BHY2dhV1E5SW14bFlXWWlQanh3WVhSb0lHUTlJazB4TnpFdU9EZzBJREV4T0M0NU9ETmhOQzQ1TXpJZ05DNDVNeklnTUNBd0lERXRNUzR3TVRnZ01pNDJNRFlnTkM0M01UVWdOQzQzTVRVZ01DQXdJREV0TVM0NE56Z2dNUzQwTXpsakxTNDBOalV1TVRrMUxURXVOek0xTGpjeU55MHlMak0yTkM0eE56WXRMakkwTmlBekxqSTVPQzB4TGpVNU15QTJMalV4TWkweUxqSTFNeUEzTGprMU5HRTBMalV6TWlBMExqVXpNaUF3SURBZ01TMHVNekV6TFM0NU16TmpMUzR5TVRFdExqazNOUzB1TURNNExURXVOell6TGpBM09DMHlMakk1TlM0eU1ESXRMamt5TVM0ek5UTXRNUzQyTVRJdU5EWTNMVEl1TVRRdE1TNHhOemN1TmprMExUSXVOalF5TGpVMk9TMHpMalUxT0MwdU1qY3lMUzQzT1RZdExqY3pNaTB4TGpBNE15MHhMamt5TVMwdU56UXpMVE11TURNMExqUTVPQzR3TVRFZ01TNDVNemt1TVRBNUlETXVNalEzSURFdU1UWTNZVFV1TVRNZ05TNHhNeUF3SURBZ01TQXhMakl4SURFdU5ERXpZeTR4TlRrdExqYzBMakU1T1MwdU9UVTRMakl6T0MweExqRTNPUzR5TURrdE1TNHlNVE11TXpJeUxURXVPRGN5TGpJM05DMHlMamN5TkdFM0xqY3pJRGN1TnpNZ01DQXdJREF0TGprd09DMHpMakUzTjJNdExqYzNNaTQwTVRVdE1TNDNPRGt1TVRrMkxUSXVNemM0TFM0ek1EUXRMak16T1MwdU1qZzNMUzQxTlRZdExqWTRNaTB1TnpZMExURXVOamt5WVRFeUxqY3pPU0F4TWk0M016a2dNQ0F3SURFdExqRTNOaTB6TGprd09XTXVOemc1TGpZd015QXhMalEzSURFdU1ERTVJREV1T1RNM0lERXVNamd6TGprME5DNDFNellnTVM0ek5EUXVOak01SURFdU56WXhJREV1TVRZM0xqRTFNaTR4T1RNdU5qUTVMamcwTWk0MU9EWWdNUzQzTlRFdExqQXhNUzR4TnpJdExqQTFNeTQzT1RVdExqUTJOQ0F4TGpJNU0yRTJMamd6SURZdU9ETWdNQ0F3SURFZ01TNHpPRFFnTWk0eU1qZGpMakUwTGpNMk9DNHlOREl1TnpRMExqTXhNU0F4TGpFMUxqRXdOeTB1TWpBM0xqSTJNUzB1TkRNNUxqVXhNUzB1TnpJeUxqUTFNeTB1TlRFekxqZzNMUzQ1T1RJZ01TNDJNRFF0TVM0eU9EUXVOamd6TFM0eU56SWdNUzR5T0MwdU1qUTVJREV1TnpJekxTNHlNelJoTlM0ek1ESWdOUzR6TURJZ01DQXdJREVnTVM0ME9EWXVNamN6V2lJdlBqd3ZaejQ4WnlCcFpEMGljMmxzYnlJK1BIQmhkR2dnWkQwaVRUVTNMakV3T0NBM01TNHlPV011TVRnNExURXhMalkxTXkweE1pNHdNUzB5TVM0ek1ETXRNamN1TWpRekxUSXhMalUxTWkweE5TNHlNelF0TGpJMUxUSTNMamN6TmlBNExqazVOUzB5Tnk0NU1qTWdNakF1TmpRNUxTNHhPRGNnTVRFdU5qVTBJREV5TGpBeElESXhMak13TkNBeU55NHlORFFnTWpFdU5UVXpJREUxTGpJek15NHlOU0F5Tnk0M016VXRPQzQ1T1RVZ01qY3VPVEl5TFRJd0xqWTFXaUlnWm1sc2JEMGlJelkyTmlJdlBqeHdZWFJvSUdROUlrMHVORFkwSURFNUxqVTBOR011TmprNUlERTJMalU0TlNBeExqUWdNek11TVRZNUlESXVNRGs0SURRNUxqYzFNaTR3TWpFZ01pNHpPREV1TkRnZ05DNHlOemd1T0RneklEVXVOVE01TGpJM055NDROaTQzTkRFZ01pNHlOelVnTVM0M056Z2dNeTQ0TmpjdU5EazBMamMxT1NBeExqSXhNaUF4TGpjZ015NHdNRElnTXk0ek16SWdNUzQzTXprZ01TNDFPRFlnTXk0ek5TQXpMakExTmlBMUxqY3pNaUEwTGpNNU9DQXpMakk1TXlBeExqZzFOU0EyTGpFMU1TQXlMak01TmlBNExqYzVNU0F5TGpnNU5pQXhMamcxTlM0ek5TQTFMakUwT1M0NU5EZ2dPUzQwT0RndU5UVTJZVE15TGpjd055QXpNaTQzTURjZ01DQXdJREFnT1M0ek1UVXRNaTR5T0Rkak1TNDROakl0TGpjMU9TQTBMalkwTWkweExqa3hOeUEzTGpZek15MDBMalFnTVM0ek5EZ3RNUzR4TWlBekxqUTBPQzB5TGpnNU55QTFMakU1TnkwMUxqazFZVEl3TGpFeE5DQXlNQzR4TVRRZ01DQXdJREFnTWk0eU5TMDFMams1T0dNdU1qRXRNVGN1TlRVeUxqUXlMVE0xTGpFd05DNDJNekl0TlRJdU5qVTNiQzAxTmk0NExqazFNbWd1TURBeFdpSWdabWxzYkQwaUkwSXpRak5DTXlJdlBqeHdZWFJvSUdROUlrMDFOeTQwT0NBeE9TNDBPREpETlRjdU5qUTFJRGt1TWpRZ05EUXVPVGM0TGpjeU55QXlPUzR4T0RjdU5EWTRJREV6TGpNNU55NHlNUzQwTmpNZ09DNHpNRE11TWprNElERTRMalUwTmk0eE16UWdNamd1TnpnNElERXlMamdnTXpjdU15QXlPQzQxT1RFZ016Y3VOVFpqTVRVdU56a3VNalU0SURJNExqY3lOQzAzTGpnek5TQXlPQzQ0T0RrdE1UZ3VNRGM0V2lJZ1ptbHNiRDBpSTBORFF5SXZQanh3WVhSb0lHUTlJazB6TUM0ek1UUWdOeTR4TXpkakxqQXdPUzB1TlRZeExTNDJPQzB4TGpBeU9DMHhMalV6T0MweExqQTBNaTB1T0RVNUxTNHdNVFF0TVM0MU5qSXVORE10TVM0MU56RXVPVGt4TFM0d01TNDFOakl1TmpnZ01TNHdNamdnTVM0MU16Z2dNUzR3TkRJdU9EVTVMakF4TlNBeExqVTJNaTB1TkRNZ01TNDFOeTB1T1RsYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFRZdU5ERTBJREk0TGpnNVlURTFMamMzTnlBeE5TNDNOemNnTUNBd0lERXRNaTR3T1RNdE1pNHhORFpqTFM0NE5UWXRNUzR3TmpNdE1pNDBOVE10TXk0d09UTXRNaTQ1TnpVdE5pNHhNVEpoTVRFdU56WTFJREV4TGpjMk5TQXdJREFnTVMwdU1Ea3pMVE11TXpBM2JESTFMalF6TFRrdU9UYzJZeTR3TkRNdU1UUXlMakU0T0M0MU5UVXVOakEwTGpnMk9DNDBOaTR6TkRZdU9UUTNMak0wSURFdU1EZzJMak16TkV3MkxqUXhNeUF5T0M0NE9EaDJMakF3TWxvaUlHWnBiR3c5SWlORk5rVTJSVFlpTHo0OGNHRjBhQ0J2Y0dGamFYUjVQU0l1TXpNaUlHUTlJazB4TGpRM055QXhOaTR3TWpsakxqSTFMUzQ1TXpFdU56QTJMVEl1TWpVNElERXVOVGN0TXk0Mk9UVXVOalUxTFRFdU1Ea3lJREV1TWpreUxURXVPREkxSURFdU56WXRNaTR6TlRndU5UZzBMUzQyTmpVZ01TNDNOell0TVM0NU16UWdNeTQyTnprdE15NHlPU0F5TGprMU15MHlMakV3TlNBMUxqWTVOaTB6TGpBMUlEY3VOekl6TFRNdU56TmhNemN1TXpVZ016Y3VNelVnTUNBd0lERWdOaTQwT0RVdE1TNDFORGRzTlM0eU5ESWdOQzR6TVRaaE1TNDBPQ0F4TGpRNElEQWdNQ0F3TFRFdU1qRTBMamsyTjB3eExqUTRJREUyTGpBemFDMHVNREF5V2lJZ1ptbHNiRDBpSXprNU9TSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNDBOQ0lnWkQwaVRURXVPREVnTWpZdU5UTXlZeTR5TURZdU5EazBMalE0TkNBeExqQTFMamcySURFdU5qTmhNVEF1TWpZMklERXdMakkyTmlBd0lEQWdNQ0F5TGpJM09DQXlMalE0Tmt3MkxqVTFNaUEzT0M0eU1tRXhOeTR5TnpJZ01UY3VNamN5SURBZ01DQXhMVE10Tnk0ME1UTk1NUzQ0TVNBeU5pNDFNekphSWlCbWFXeHNQU0lqUlRaRk5rVTJJaTgrUEhCaGRHZ2daRDBpYlRNekxqQTVNaUEwT1M0ME5ERXROaTR6T0RFZ01UVXVNakV4Y3kwMkxqQTNPQzB4TVM0eE5Ua2dOaTR6T0RFdE1UVXVNakZhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEhCaGRHZ2daRDBpYlRJMkxqY3lOU0EyTkM0NE5UZ3RMakE1TVMwdU1UYzFZeTB1TURJMkxTNHdORGt0TWk0Mk16UXROQzQ1TWpNdExqZzJOeTA1TGpNM0lERXVNRFUzTFRJdU56RTNJRE11TlRFNExUUXVOekkxSURjdU15MDFMamswTm13dU1UZzNMUzR3TmpFdE5pNDFNeUF4TlM0MU5USmFiVFl1TWpFeUxURTFMakkyT0dNdE15NDJNakVnTVM0eU1UY3ROUzQ1T1RFZ015NHhOamd0Tnk0d01qSWdOUzQzT1RndE1TNDFNemdnTXk0NU1EZ3VNelUxSURndU1UWTJMamM0T0NBNUxqQTFOR3cyTGpJek5DMHhOQzQ0TlRKYVRUSTRMakE1TXlBMk15NDNNemRzTkM0ME9EUXRNVEF1T0Rkek55NHpOalVnTmk0ek16Y3ROQzQwT0RRZ01UQXVPRGRhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEM5blBqeG5JR2xrUFNKQ1JVRk9JajQ4Y21WamRDQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnM0lERXVNalkxTFRNdU5UQTBJRGt1TXpaVExqSTVPQ0F6TGprNU9TQTNMalk0TnlBeExqSTJObHB0TFRJdU5qa3hJRGd1TnpnZ01pNDBOakl0Tmk0Mk9URnpOQzQxTXpnZ015NDJOeTB5TGpRMk1pQTJMalk1TVZvaUlHWnBiR3c5SWlObVptWWlMejQ4TDJjK1BHY2dhV1E5SWtKRlFVNHpRMUpXSWo0OGNtVmpkQ0I1UFNJdU5TSWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE55QXhMamMyTkMwekxqVXdOQ0E1TGpNMlV5NHlPVGdnTkM0ME9Ua2dOeTQyT0RjZ01TNDNOalZhSWlCbWFXeHNQU0lqWm1abUlpOCtQSEJoZEdnZ1pEMGlUVGd1TVRNeUlEZ3VNRGM0WXkwdU5EWTJMalkwTFRFdU1qazNJREV1TXpJekxUSXVOamsxSURFdU9Ua3liREl1TVRJMkxUVXVOemMzWXk0d09Ea3VNRGt1TVRrekxqSXdOQzR6TGpNek9DNHpNRE11TXpjMUxqWXlOUzQ0T1RFdU56UTBJREV1TkRnMExqRXhOeTQxT0RNdU1EUWdNUzR5TlRNdExqUTNOU0F4TGprMk0xb2lJR1pwYkd3OUluVnliQ2dqWVNraUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMWGRwWkhSb1BTSXVOU0l2UGp4a1pXWnpQanhzYVc1bFlYSkhjbUZrYVdWdWRDQnBaRDBpWVNJZ2VERTlJall1T1RVaUlIa3hQU0l6TGpnMU15SWdlREk5SWpZdU9UVWlJSGt5UFNJeE1DNDFORFFpSUdkeVlXUnBaVzUwVlc1cGRITTlJblZ6WlhKVGNHRmpaVTl1VlhObElqNDhjM1J2Y0NCemRHOXdMV052Ykc5eVBTSWpPREl3TWpBeUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU1UZ3lJaUJ6ZEc5d0xXTnZiRzl5UFNJalJqY3hSVEExSWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TlRFMklpQnpkRzl3TFdOdmJHOXlQU0lqUmpCR05UQTNJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOek0wSWlCemRHOXdMV052Ykc5eVBTSWpPRFZEUkRjMUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeElpQnpkRzl3TFdOdmJHOXlQU0lqTURJNVJFWkNJaTgrUEM5c2FXNWxZWEpIY21Ga2FXVnVkRDQ4TDJSbFpuTStQQzluUGp4bklHbGtQU0oxY2tKRlFVNGlQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RjZ01TNHlOalV0TXk0MU1EUWdPUzR6TmxNdU1qazRJRE11T1RrNUlEY3VOamczSURFdU1qWTJXbTB0TWk0Mk9URWdPQzQzT0NBeUxqUTJNaTAyTGpZNU1YTTBMalV6T0NBekxqWTNMVEl1TkRZeUlEWXVOamt4V2lJZ1ptbHNiRDBpSTJabVppSXZQand2Wno0OFp5QnBaRDBpUWtWQlRrVlVTQ0krUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE5DQXhMakkyTlMwekxqVXdOU0E1TGpNMll5NHdNRE1nTUMwekxqZzROQzAyTGpZeU5TQXpMalV3TlMwNUxqTTJXaUlnWm1sc2JEMGlJMlptWmlJdlBqeHdZWFJvSUdROUlrMDRMamsxTWlBMkxqazRObUV1TURZekxqQTJNeUF3SURBZ01TMHVNREl5TGpBd00yTXRMamN4TGpFekxURXVOREkwTGpJMU5TMHlMakV6TkM0ek9ERXRMakk0TVM0d05USXRMalUyTlM0eE1ETXRMamcwTmk0eE5USmhMakF6Tmk0d016WWdNQ0F3SURFdExqQXlOaUF3YkRJdU1UUXROUzQyTWpVdU1EQTBMUzR3TUROakxqSTVOeUF4TGpjd01pNDFPU0F6TGpNNU5DNDRPRFFnTlM0d09USmFiUzB1TVRnM0xqUTNPR010TVM0eU5qWXVPRFU1TFRJdU5UTXhJREV1TnpJeExUTXVPQ0F5TGpVNGJDNDNPREV0TWk0d05UUmpMakF3Tnk0d01EUXVNREV6SURBZ0xqQXlNeUF3SUM0M05Ua3RMakV6TWlBeExqVXhOQzB1TWpZNElESXVNamN0TGpSc0xqWTVOeTB1TVRJMkxqQXpMUzR3TURaakxTNHdNRFF1TURBeklEQWdMakF3TmlBd0lDNHdNRFphSWlCbWFXeHNQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0oxY2tKRlFVNUZWRWdpUGp4eVpXTjBJSGRwWkhSb1BTSXhNaUlnYUdWcFoyaDBQU0l4TWlJZ2NuZzlJallpSUdacGJHdzlJaU0zUmpVMU16TWlMejQ4Y0dGMGFDQmtQU0p0Tnk0Mk9EUWdNUzR5TmpVdE15NDFNRFVnT1M0ek5tTXVNREF6SURBdE15NDRPRFF0Tmk0Mk1qVWdNeTQxTURVdE9TNHpObG9pSUdacGJHdzlJaU5tWm1ZaUx6NDhjR0YwYUNCa1BTSk5PQzQ1TlRJZ05pNDVPRFpoTGpBMk15NHdOak1nTUNBd0lERXRMakF5TWk0d01ETmpMUzQzTVM0eE15MHhMalF5TkM0eU5UVXRNaTR4TXpRdU16Z3hMUzR5T0RFdU1EVXlMUzQxTmpVdU1UQXpMUzQ0TkRZdU1UVXlZUzR3TXpZdU1ETTJJREFnTUNBeExTNHdNallnTUd3eUxqRTBMVFV1TmpJMUxqQXdOQzB1TURBell5NHlPVGNnTVM0M01ESXVOVGtnTXk0ek9UUXVPRGcwSURVdU1Ea3lXbTB0TGpFNE55NDBOemhqTFRFdU1qWTJMamcxT1MweUxqVXpNU0F4TGpjeU1TMHpMamdnTWk0MU9Hd3VOemd4TFRJdU1EVTBZeTR3TURjdU1EQTBMakF4TXlBd0lDNHdNak1nTUNBdU56VTVMUzR4TXpJZ01TNDFNVFF0TGpJMk9DQXlMakkzTFM0MGJDNDJPVGN0TGpFeU5pNHdNeTB1TURBMll5MHVNREEwTGpBd015QXdJQzR3TURZZ01DQXVNREEyV2lJZ1ptbHNiRDBpSXpBd01DSXZQand2Wno0OFp5QnBaRDBpYkdWaFpsSnZkeUkrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTUNJZ2VUMGlNQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweE1pSWdlVDBpTFRjaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXRNalFpSUhrOUlpMHhOQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkwek5pSWdlVDBpTFRJeElpOCtQQzluUGp3dlpHVm1jejQ4Y21WamRDQjNhV1IwYUQwaU1qVTFJaUJvWldsbmFIUTlJak0xTUNJZ2NuZzlJakV3SWlCbWFXeHNQU0lqTWpVek16STJJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYzJsc2J5SWdlRDBpT1RraUlIazlJalUxSWk4K1BHY2dhV1E5SW1Gc2JGQnNiM1FpSUdOc2FYQXRjR0YwYUQwaWRYSnNLQ05pYjNKa1pYSk5ZWE5yS1NJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWkweE5qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVEUyTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTm1kV3hzVEdWaFpsQnNiM1FpSUhnOUlqQWlJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l4TXpnaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXRNVEkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJdE9EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVGcwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTUNJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l0TmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM05wYkc4aUlIZzlJalEzSWlCNVBTSTFOU0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpjcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXpOaUlnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObWRXeHNUR1ZoWmxCc2IzUWlJSGc5SWpFek9DSWdlVDBpTXpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXROamtpSUhrOUlqYzJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTmpraUlIazlJamMySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTUNJZ2VUMGlNVEUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlNVFUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJeE5UWWlJQzgrUEM5blBqeHlaV04wSUhnOUlqQWlJSGs5SWpBaUlIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNakFpSUhKNFBTSTFJaUJtYVd4c1BTSWpNalF5TkRJMElpOCtQSFJsZUhRZ2VEMGlNVEFpSUhrOUlqRTBMalVpSUdadmJuUXRjMmw2WlQwaU1USWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGljM1JoY25RaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQa0pGUVU1RlZFZ2dSR1Z3YjNOcGREd3ZkR1Y0ZEQ0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOQ1JVRk9SVlJJSWlCNFBTSXlOREFpSUhrOUlqUWlJQzgrUEhKbFkzUWdlRDBpTUNJZ2VUMGlNek13SWlCM2FXUjBhRDBpTWpVMUlpQm9aV2xuYUhROUlqSXdJaUJ5ZUQwaU5TSWdabWxzYkQwaUl6STBNalF5TkNJdlBqeDBaWGgwSUhnOUlqRXlOeUlnZVQwaU16UXpJaUJtYjI1MExYTnBlbVU5SWpFd0lpQm1hV3hzUFNKWGFHbDBaU0lnZEdWNGRDMWhibU5vYjNJOUltMXBaR1JzWlNJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStQSFJ6Y0dGdVBqeGhibWx0WVhSbElHRjBkSEpwWW5WMFpVNWhiV1U5SW5naUlHWnliMjA5SWpNM05TSWdkRzg5SWpVd0lpQmtkWEk5SWpFd2N5SWdjbVZ3WldGMFEyOTFiblE5SW1sdVpHVm1hVzVwZEdVaUlDOCtNSGhpWldFd1pURXhNamd5WlRKaVlqVTRPVE5pWldObE1URXdZMll4T1RrMU1ERmxPRGN5WW1Ga1BDOTBjM0JoYmo0OEwzUmxlSFErUEhSbGVIUWdlRDBpTVRJM0lpQjVQU0l6TkRNaUlHWnZiblF0YzJsNlpUMGlNVEFpSUdacGJHdzlJbGRvYVhSbElpQjBaWGgwTFdGdVkyaHZjajBpYldsa1pHeGxJaUJtYjI1MExXWmhiV2xzZVQwaVpuVjBkWEpoSWo0OGRITndZVzQrUEdGdWFXMWhkR1VnWVhSMGNtbGlkWFJsVG1GdFpUMGllQ0lnWm5KdmJUMGlOVEFpSUhSdlBTSXRNamMxSWlCa2RYSTlJakV3Y3lJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUM4K01IaGlaV0V3WlRFeE1qZ3laVEppWWpVNE9UTmlaV05sTVRFd1kyWXhPVGsxTURGbE9EY3lZbUZrUEM5MGMzQmhiajQ4TDNSbGVIUStQSFJsZUhRZ2VEMGlNak0xSWlCNVBTSXhOQzQxSWlCbWIyNTBMWE5wZW1VOUlqRXlJaUJtYVd4c1BTSlhhR2wwWlNJZ2RHVjRkQzFoYm1Ob2IzSTlJbVZ1WkNJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStVM1JsYlRvZ0xURXVOelU1TWpGbE1UTThMM1JsZUhRK1BDOXpkbWMrIn0= \ No newline at end of file diff --git a/protocol/test/data/base64EncodedImageUrBean.txt b/protocol/test/data/base64EncodedImageUrBean.txt index 9d20629db0..feb8b02e1f 100644 --- a/protocol/test/data/base64EncodedImageUrBean.txt +++ b/protocol/test/data/base64EncodedImageUrBean.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IHVyQkVBTlxuVG9rZW4gQWRkcmVzczogMHgxYmVhMDA1MGU2M2UwNWZiYjVkOGJhMmYxMGNmNTgwMGI2MjI0NDQ5XG5JZDogMHgxYmVhMDA1MGU2M2UwNWZiYjVkOGJhMmYxMGNmNTgwMGI2MjI0NDQ5MDAwMDAwMDAwMDAwMDAwMDAwMDAwNDAwXG5zdGVtOiAxMDI0XG5pbml0YWwgc3RhbGsgcGVyIEJEVjogMTAwMDBcbmdyb3duIHN0YWxrIHBlciBCRFY6IDk3OFxuc3RhbGsgZ3Jvd24gcGVyIEJEViBwZXIgc2Vhc29uOiAyMDAwMDAwXG5cbkRJU0NMQUlNRVI6IER1ZSBkaWxpZ2VuY2UgaXMgaW1wZXJhdGl2ZSB3aGVuIGFzc2Vzc2luZyB0aGlzIE5GVC4gT3BlbnNlYSBhbmQgb3RoZXIgTkZUIG1hcmtldHBsYWNlcyBjYWNoZSB0aGUgc3ZnIG91dHB1dCBhbmQgdGh1cywgbWF5IHJlcXVpcmUgdGhlIHVzZXIgdG8gcmVmcmVzaCB0aGUgbWV0YWRhdGEgdG8gcHJvcGVybHkgc2hvdyB0aGUgY29ycmVjdCB2YWx1ZXMuIiwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmxKdmR5SWdlRDBpTFRNMUlpQjVQU0l3SWlCbWFXeHNQU0lqUVRoRE9ETkJJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhMMmMrUEdjZ2FXUTlJbXhsWVdZaVBqeHdZWFJvSUdROUlrMHhOekV1T0RnMElERXhPQzQ1T0ROaE5DNDVNeklnTkM0NU16SWdNQ0F3SURFdE1TNHdNVGdnTWk0Mk1EWWdOQzQzTVRVZ05DNDNNVFVnTUNBd0lERXRNUzQ0TnpnZ01TNDBNemxqTFM0ME5qVXVNVGsxTFRFdU56TTFMamN5TnkweUxqTTJOQzR4TnpZdExqSTBOaUF6TGpJNU9DMHhMalU1TXlBMkxqVXhNaTB5TGpJMU15QTNMamsxTkdFMExqVXpNaUEwTGpVek1pQXdJREFnTVMwdU16RXpMUzQ1TXpOakxTNHlNVEV0TGprM05TMHVNRE00TFRFdU56WXpMakEzT0MweUxqSTVOUzR5TURJdExqa3lNUzR6TlRNdE1TNDJNVEl1TkRZM0xUSXVNVFF0TVM0eE56Y3VOamswTFRJdU5qUXlMalUyT1MwekxqVTFPQzB1TWpjeUxTNDNPVFl0TGpjek1pMHhMakE0TXkweExqa3lNUzB1TnpRekxUTXVNRE0wTGpRNU9DNHdNVEVnTVM0NU16a3VNVEE1SURNdU1qUTNJREV1TVRZM1lUVXVNVE1nTlM0eE15QXdJREFnTVNBeExqSXhJREV1TkRFell5NHhOVGt0TGpjMExqRTVPUzB1T1RVNExqSXpPQzB4TGpFM09TNHlNRGt0TVM0eU1UTXVNekl5TFRFdU9EY3lMakkzTkMweUxqY3lOR0UzTGpjeklEY3VOek1nTUNBd0lEQXRMamt3T0MwekxqRTNOMk10TGpjM01pNDBNVFV0TVM0M09Ea3VNVGsyTFRJdU16YzRMUzR6TURRdExqTXpPUzB1TWpnM0xTNDFOVFl0TGpZNE1pMHVOelkwTFRFdU5qa3lZVEV5TGpjek9TQXhNaTQzTXprZ01DQXdJREV0TGpFM05pMHpMamt3T1dNdU56ZzVMall3TXlBeExqUTNJREV1TURFNUlERXVPVE0zSURFdU1qZ3pMamswTkM0MU16WWdNUzR6TkRRdU5qTTVJREV1TnpZeElERXVNVFkzTGpFMU1pNHhPVE11TmpRNUxqZzBNaTQxT0RZZ01TNDNOVEV0TGpBeE1TNHhOekl0TGpBMU15NDNPVFV0TGpRMk5DQXhMakk1TTJFMkxqZ3pJRFl1T0RNZ01DQXdJREVnTVM0ek9EUWdNaTR5TWpkakxqRTBMak0yT0M0eU5ESXVOelEwTGpNeE1TQXhMakUxTGpFd055MHVNakEzTGpJMk1TMHVORE01TGpVeE1TMHVOekl5TGpRMU15MHVOVEV6TGpnM0xTNDVPVElnTVM0Mk1EUXRNUzR5T0RRdU5qZ3pMUzR5TnpJZ01TNHlPQzB1TWpRNUlERXVOekl6TFM0eU16UmhOUzR6TURJZ05TNHpNRElnTUNBd0lERWdNUzQwT0RZdU1qY3pXaUl2UGp3dlp6NDhaeUJwWkQwaWMybHNieUkrUEhCaGRHZ2daRDBpVFRVM0xqRXdPQ0EzTVM0eU9XTXVNVGc0TFRFeExqWTFNeTB4TWk0d01TMHlNUzR6TURNdE1qY3VNalF6TFRJeExqVTFNaTB4TlM0eU16UXRMakkxTFRJM0xqY3pOaUE0TGprNU5TMHlOeTQ1TWpNZ01qQXVOalE1TFM0eE9EY2dNVEV1TmpVMElERXlMakF4SURJeExqTXdOQ0F5Tnk0eU5EUWdNakV1TlRVeklERTFMakl6TXk0eU5TQXlOeTQzTXpVdE9DNDVPVFVnTWpjdU9USXlMVEl3TGpZMVdpSWdabWxzYkQwaUl6WTJOaUl2UGp4d1lYUm9JR1E5SWswdU5EWTBJREU1TGpVME5HTXVOams1SURFMkxqVTROU0F4TGpRZ016TXVNVFk1SURJdU1EazRJRFE1TGpjMU1pNHdNakVnTWk0ek9ERXVORGdnTkM0eU56Z3VPRGd6SURVdU5UTTVMakkzTnk0NE5pNDNOREVnTWk0eU56VWdNUzQzTnpnZ015NDROamN1TkRrMExqYzFPU0F4TGpJeE1pQXhMamNnTXk0d01ESWdNeTR6TXpJZ01TNDNNemtnTVM0MU9EWWdNeTR6TlNBekxqQTFOaUExTGpjek1pQTBMak01T0NBekxqSTVNeUF4TGpnMU5TQTJMakUxTVNBeUxqTTVOaUE0TGpjNU1TQXlMamc1TmlBeExqZzFOUzR6TlNBMUxqRTBPUzQ1TkRnZ09TNDBPRGd1TlRVMllUTXlMamN3TnlBek1pNDNNRGNnTUNBd0lEQWdPUzR6TVRVdE1pNHlPRGRqTVM0NE5qSXRMamMxT1NBMExqWTBNaTB4TGpreE55QTNMall6TXkwMExqUWdNUzR6TkRndE1TNHhNaUF6TGpRME9DMHlMamc1TnlBMUxqRTVOeTAxTGprMVlUSXdMakV4TkNBeU1DNHhNVFFnTUNBd0lEQWdNaTR5TlMwMUxqazVPR011TWpFdE1UY3VOVFV5TGpReUxUTTFMakV3TkM0Mk16SXROVEl1TmpVM2JDMDFOaTQ0TGprMU1tZ3VNREF4V2lJZ1ptbHNiRDBpSTBJelFqTkNNeUl2UGp4d1lYUm9JR1E5SWswMU55NDBPQ0F4T1M0ME9ESkROVGN1TmpRMUlEa3VNalFnTkRRdU9UYzRMamN5TnlBeU9TNHhPRGN1TkRZNElERXpMak01Tnk0eU1TNDBOak1nT0M0ek1ETXVNams0SURFNExqVTBOaTR4TXpRZ01qZ3VOemc0SURFeUxqZ2dNemN1TXlBeU9DNDFPVEVnTXpjdU5UWmpNVFV1TnprdU1qVTRJREk0TGpjeU5DMDNMamd6TlNBeU9DNDRPRGt0TVRndU1EYzRXaUlnWm1sc2JEMGlJME5EUXlJdlBqeHdZWFJvSUdROUlrMHpNQzR6TVRRZ055NHhNemRqTGpBd09TMHVOVFl4TFM0Mk9DMHhMakF5T0MweExqVXpPQzB4TGpBME1pMHVPRFU1TFM0d01UUXRNUzQxTmpJdU5ETXRNUzQxTnpFdU9Ua3hMUzR3TVM0MU5qSXVOamdnTVM0d01qZ2dNUzQxTXpnZ01TNHdOREl1T0RVNUxqQXhOU0F4TGpVMk1pMHVORE1nTVM0MU55MHVPVGxhSWlCbWFXeHNQU0lqTmpZMklpOCtQSEJoZEdnZ1pEMGlUVFl1TkRFMElESTRMamc1WVRFMUxqYzNOeUF4TlM0M056Y2dNQ0F3SURFdE1pNHdPVE10TWk0eE5EWmpMUzQ0TlRZdE1TNHdOak10TWk0ME5UTXRNeTR3T1RNdE1pNDVOelV0Tmk0eE1USmhNVEV1TnpZMUlERXhMamMyTlNBd0lEQWdNUzB1TURrekxUTXVNekEzYkRJMUxqUXpMVGt1T1RjMll5NHdORE11TVRReUxqRTRPQzQxTlRVdU5qQTBMamcyT0M0ME5pNHpORFl1T1RRM0xqTTBJREV1TURnMkxqTXpORXcyTGpReE15QXlPQzQ0T0RoMkxqQXdNbG9pSUdacGJHdzlJaU5GTmtVMlJUWWlMejQ4Y0dGMGFDQnZjR0ZqYVhSNVBTSXVNek1pSUdROUlrMHhMalEzTnlBeE5pNHdNamxqTGpJMUxTNDVNekV1TnpBMkxUSXVNalU0SURFdU5UY3RNeTQyT1RVdU5qVTFMVEV1TURreUlERXVNamt5TFRFdU9ESTFJREV1TnpZdE1pNHpOVGd1TlRnMExTNDJOalVnTVM0M056WXRNUzQ1TXpRZ015NDJOemt0TXk0eU9TQXlMamsxTXkweUxqRXdOU0ExTGpZNU5pMHpMakExSURjdU56SXpMVE11TnpOaE16Y3VNelVnTXpjdU16VWdNQ0F3SURFZ05pNDBPRFV0TVM0MU5EZHNOUzR5TkRJZ05DNHpNVFpoTVM0ME9DQXhMalE0SURBZ01DQXdMVEV1TWpFMExqazJOMHd4TGpRNElERTJMakF6YUMwdU1EQXlXaUlnWm1sc2JEMGlJems1T1NJdlBqeHdZWFJvSUc5d1lXTnBkSGs5SWk0ME5DSWdaRDBpVFRFdU9ERWdNall1TlRNeVl5NHlNRFl1TkRrMExqUTROQ0F4TGpBMUxqZzJJREV1TmpOaE1UQXVNalkySURFd0xqSTJOaUF3SURBZ01DQXlMakkzT0NBeUxqUTROa3cyTGpVMU1pQTNPQzR5TW1FeE55NHlOeklnTVRjdU1qY3lJREFnTUNBeExUTXROeTQwTVROTU1TNDRNU0F5Tmk0MU16SmFJaUJtYVd4c1BTSWpSVFpGTmtVMklpOCtQSEJoZEdnZ1pEMGliVE16TGpBNU1pQTBPUzQwTkRFdE5pNHpPREVnTVRVdU1qRXhjeTAyTGpBM09DMHhNUzR4TlRrZ05pNHpPREV0TVRVdU1qRmFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQSEJoZEdnZ1pEMGliVEkyTGpjeU5TQTJOQzQ0TlRndExqQTVNUzB1TVRjMVl5MHVNREkyTFM0d05Ea3RNaTQyTXpRdE5DNDVNak10TGpnMk55MDVMak0zSURFdU1EVTNMVEl1TnpFM0lETXVOVEU0TFRRdU56STFJRGN1TXkwMUxqazBObXd1TVRnM0xTNHdOakV0Tmk0MU15QXhOUzQxTlRKYWJUWXVNakV5TFRFMUxqSTJPR010TXk0Mk1qRWdNUzR5TVRjdE5TNDVPVEVnTXk0eE5qZ3ROeTR3TWpJZ05TNDNPVGd0TVM0MU16Z2dNeTQ1TURndU16VTFJRGd1TVRZMkxqYzRPQ0E1TGpBMU5HdzJMakl6TkMweE5DNDROVEphVFRJNExqQTVNeUEyTXk0M016ZHNOQzQwT0RRdE1UQXVPRGR6Tnk0ek5qVWdOaTR6TXpjdE5DNDBPRFFnTVRBdU9EZGFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQQzluUGp4bklHbGtQU0pDUlVGT0lqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU1qWTFMVE11TlRBMElEa3VNelpUTGpJNU9DQXpMams1T1NBM0xqWTROeUF4TGpJMk5scHRMVEl1TmpreElEZ3VOemdnTWk0ME5qSXROaTQyT1RGek5DNDFNemdnTXk0Mk55MHlMalEyTWlBMkxqWTVNVm9pSUdacGJHdzlJaU5tWm1ZaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0elExSldJajQ4Y21WamRDQjVQU0l1TlNJZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TnlBeExqYzJOQzB6TGpVd05DQTVMak0yVXk0eU9UZ2dOQzQwT1RrZ055NDJPRGNnTVM0M05qVmFJaUJtYVd4c1BTSWpabVptSWk4K1BIQmhkR2dnWkQwaVRUZ3VNVE15SURndU1EYzRZeTB1TkRZMkxqWTBMVEV1TWprM0lERXVNekl6TFRJdU5qazFJREV1T1RreWJESXVNVEkyTFRVdU56YzNZeTR3T0RrdU1Ea3VNVGt6TGpJd05DNHpMak16T0M0ek1ETXVNemMxTGpZeU5TNDRPVEV1TnpRMElERXVORGcwTGpFeE55NDFPRE11TURRZ01TNHlOVE10TGpRM05TQXhMamsyTTFvaUlHWnBiR3c5SW5WeWJDZ2pZU2tpSUhOMGNtOXJaVDBpSTJabVppSWdjM1J5YjJ0bExYZHBaSFJvUFNJdU5TSXZQanhrWldaelBqeHNhVzVsWVhKSGNtRmthV1Z1ZENCcFpEMGlZU0lnZURFOUlqWXVPVFVpSUhreFBTSXpMamcxTXlJZ2VESTlJall1T1RVaUlIa3lQU0l4TUM0MU5EUWlJR2R5WVdScFpXNTBWVzVwZEhNOUluVnpaWEpUY0dGalpVOXVWWE5sSWo0OGMzUnZjQ0J6ZEc5d0xXTnZiRzl5UFNJak9ESXdNakF5SWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TVRneUlpQnpkRzl3TFdOdmJHOXlQU0lqUmpjeFJUQTFJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOVEUySWlCemRHOXdMV052Ykc5eVBTSWpSakJHTlRBM0lpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU56TTBJaUJ6ZEc5d0xXTnZiRzl5UFNJak9EVkRSRGMxSWk4K1BITjBiM0FnYjJabWMyVjBQU0l4SWlCemRHOXdMV052Ykc5eVBTSWpNREk1UkVaQ0lpOCtQQzlzYVc1bFlYSkhjbUZrYVdWdWRENDhMMlJsWm5NK1BDOW5QanhuSUdsa1BTSjFja0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNM1JqVTFNek1pTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSjFja0pGUVU1RlZFZ2lQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RRZ01TNHlOalV0TXk0MU1EVWdPUzR6Tm1NdU1EQXpJREF0TXk0NE9EUXROaTQyTWpVZ015NDFNRFV0T1M0ek5sb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNDVOVElnTmk0NU9EWmhMakEyTXk0d05qTWdNQ0F3SURFdExqQXlNaTR3TUROakxTNDNNUzR4TXkweExqUXlOQzR5TlRVdE1pNHhNelF1TXpneExTNHlPREV1TURVeUxTNDFOalV1TVRBekxTNDRORFl1TVRVeVlTNHdNell1TURNMklEQWdNQ0F4TFM0d01qWWdNR3d5TGpFMExUVXVOakkxTGpBd05DMHVNREF6WXk0eU9UY2dNUzQzTURJdU5Ua2dNeTR6T1RRdU9EZzBJRFV1TURreVdtMHRMakU0Tnk0ME56aGpMVEV1TWpZMkxqZzFPUzB5TGpVek1TQXhMamN5TVMwekxqZ2dNaTQxT0d3dU56Z3hMVEl1TURVMFl5NHdNRGN1TURBMExqQXhNeUF3SUM0d01qTWdNQ0F1TnpVNUxTNHhNeklnTVM0MU1UUXRMakkyT0NBeUxqSTNMUzQwYkM0Mk9UY3RMakV5Tmk0d015MHVNREEyWXkwdU1EQTBMakF3TXlBd0lDNHdNRFlnTUNBdU1EQTJXaUlnWm1sc2JEMGlJekF3TUNJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1JaUI0UFNJdE1qUWlJSGs5SWkweE5DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB6TmlJZ2VUMGlMVEl4SWk4K1BDOW5Qand2WkdWbWN6NDhjbVZqZENCM2FXUjBhRDBpTWpVMUlpQm9aV2xuYUhROUlqTTFNQ0lnY25nOUlqRXdJaUJtYVd4c1BTSWpNalV6TXpJMklpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjMmxzYnlJZ2VEMGlPVGtpSUhrOUlqVTFJaTgrUEdjZ2FXUTlJbUZzYkZCc2IzUWlJR05zYVhBdGNHRjBhRDBpZFhKc0tDTmliM0prWlhKTllYTnJLU0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXROamtpSUhrOUlpMHhOalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVEUyTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpBaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJeE16Z2lJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXRNVEkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRnMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNVE00SWlCNVBTSXRORFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzTnBiRzhpSUhnOUlqUTNJaUI1UFNJMU5TSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMamNwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l6TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpFek9DSWdlVDBpTXpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JoY25ScFlXeE1aV0ZtVUd4dmRDSWdlRDBpTmpraUlIazlJamMySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTFRFek9DSWdlVDBpTVRFMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlNQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNVE00SWlCNVBTSXhNVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlNVFUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l4TlRZaUlDOCtQQzluUGp4eVpXTjBJSGc5SWpBaUlIazlJakFpSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU1qQWlJSEo0UFNJMUlpQm1hV3hzUFNJak1qUXlOREkwSWk4K1BIUmxlSFFnZUQwaU1UQWlJSGs5SWpFMExqVWlJR1p2Ym5RdGMybDZaVDBpTVRJaUlHWnBiR3c5SWxkb2FYUmxJaUIwWlhoMExXRnVZMmh2Y2owaWMzUmhjblFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBuVnlRa1ZCVGlCRVpYQnZjMmwwUEM5MFpYaDBQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM1Z5UWtWQlRpSWdlRDBpTWpRd0lpQjVQU0kwSWlBdlBqeHlaV04wSUhnOUlqQWlJSGs5SWpNek1DSWdkMmxrZEdnOUlqSTFOU0lnYUdWcFoyaDBQU0l5TUNJZ2NuZzlJalVpSUdacGJHdzlJaU15TkRJME1qUWlMejQ4ZEdWNGRDQjRQU0l4TWpjaUlIazlJak0wTXlJZ1ptOXVkQzF6YVhwbFBTSXhNQ0lnWm1sc2JEMGlWMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0p0YVdSa2JHVWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGp4MGMzQmhiajQ4WVc1cGJXRjBaU0JoZEhSeWFXSjFkR1ZPWVcxbFBTSjRJaUJtY205dFBTSXpOelVpSUhSdlBTSTFNQ0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNE1XSmxZVEF3TlRCbE5qTmxNRFZtWW1JMVpEaGlZVEptTVRCalpqVTRNREJpTmpJeU5EUTBPVHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqRXlOeUlnZVQwaU16UXpJaUJtYjI1MExYTnBlbVU5SWpFd0lpQm1hV3hzUFNKWGFHbDBaU0lnZEdWNGRDMWhibU5vYjNJOUltMXBaR1JzWlNJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStQSFJ6Y0dGdVBqeGhibWx0WVhSbElHRjBkSEpwWW5WMFpVNWhiV1U5SW5naUlHWnliMjA5SWpVd0lpQjBiejBpTFRJM05TSWdaSFZ5UFNJeE1ITWlJSEpsY0dWaGRFTnZkVzUwUFNKcGJtUmxabWx1YVhSbElpQXZQakI0TVdKbFlUQXdOVEJsTmpObE1EVm1ZbUkxWkRoaVlUSm1NVEJqWmpVNE1EQmlOakl5TkRRME9Ud3ZkSE53WVc0K1BDOTBaWGgwUGp4MFpYaDBJSGc5SWpJek5TSWdlVDBpTVRRdU5TSWdabTl1ZEMxemFYcGxQU0l4TWlJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKbGJtUWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGxOMFpXMDZJREV3TWpROEwzUmxlSFErUEM5emRtYysifQ== \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJ1ckJFQU4ifSwgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiBBZGRyZXNzIiwgInZhbHVlIjogIjB4MWJlYTAwNTBlNjNlMDVmYmI1ZDhiYTJmMTBjZjU4MDBiNjIyNDQ0OSJ9LCB7ICJ0cmFpdF90eXBlIjogIklkIiwgInZhbHVlIjogIjB4MWJlYTAwNTBlNjNlMDVmYmI1ZDhiYTJmMTBjZjU4MDBiNjIyNDQ0OTAwMDAwMDAwMDAwMDAwMDAwMDAwMDQwMCJ9LCB7ICJ0cmFpdF90eXBlIjogInN0ZW0iLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDEwMjR9LCB7ICJ0cmFpdF90eXBlIjogImluaXRhbCBzdGFsayBwZXIgQkRWIiwgImRpc3BsYXlfdHlwZSI6ICJudW1iZXIiLCAidmFsdWUiOiAxMDAwMH0sIHsgInRyYWl0X3R5cGUiOiAiZ3Jvd24gc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogOTc4fSwgeyAidHJhaXRfdHlwZSI6ICJzdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb24iLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDIwMDAwMDAsICJpbWFnZSI6ICJkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUJqYkdGemN6MGljM1puUW05a2VTSWdkMmxrZEdnOUlqSTFOU0lnYUdWcFoyaDBQU0l6TlRBaUlIWnBaWGRDYjNnOUlqQWdNQ0F5TlRVZ016VXdJaUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSGh0Ykc1ek9uaHNhVzVyUFNKb2RIUndPaTh2ZDNkM0xuY3pMbTl5Wnk4eE9UazVMM2hzYVc1cklqNDhaR1ZtY3o0OFp5QnBaRDBpY0d4dmRDSStQSEJoZEdnZ1pEMGlUVGM1TGpVM01qZ2dNVEk1TGpJMk5Vd3hNamN1TkRZNUlERTFOaTQ0TXpOTU1UYzFMalEwTXlBeE1qa3VNalExVERFeU55NDBOamtnTVRBeExqWTVOMHczT1M0MU56STRJREV5T1M0eU5qVmFJaUJtYVd4c1BTSWpPVFEwUVRJM0lpOCtQSEJoZEdnZ1pEMGlUVGM1TGpVek16SWdNVE16TGpReU5rdzNPUzQxTnpJM0lERXlPUzR5TmpWTU1USTNMalEyT1NBeE5UWXVPRE16VERFeU55NDFNRGNnTVRZd0xqa3dPRXczT1M0MU16TXlJREV6TXk0ME1qWmFJaUJtYVd4c1BTSWpOelV6T1RGR0lpOCtQSEJoZEdnZ1pEMGlUVEUzTlM0ME5qY2dNVE16TGpSTU1UYzFMalEwTXlBeE1qa3VNalExVERFeU55NDBOamtnTVRVMkxqZ3pNMHd4TWpjdU5UQTNJREUyTUM0NU1EaE1NVGMxTGpRMk55QXhNek11TkZvaUlHWnBiR3c5SWlNMk56TXpNVVVpTHo0OEwyYytQR2NnYVdROUltWjFiR3hNWldGbVVHeHZkQ0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0d4dmRDSWdlRDBpTFRNMUlpQjVQU0l3SWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5zWldGbVVtOTNJaUI0UFNJdE16VWlJSGs5SWpBaUlHWnBiR3c5SWlOQk9FTTRNMEVpSUhSeVlXNXpabTl5YlQwaWMyTmhiR1VvTVM0MEtTSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdaU2IzY2lJSGc5SWkwME55SWdlVDBpTnlJZ1ptbHNiRDBpSXpnNVFUWXlSaUlnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmxKdmR5SWdlRDBpTFRZd0lpQjVQU0l4TkNJZ1ptbHNiRDBpSTBFNFF6Z3pRU0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmxKdmR5SWdlRDBpTFRjeklpQjVQU0l5TVNJZ1ptbHNiRDBpSXpnNVFUWXlSaUlnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0psYlhCMGVWQnNiM1FpUGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNCc2IzUWlJSGc5SWkwek5TSWdlVDBpTUNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKd1lYSjBhV0ZzVEdWaFpsSnZkeUkrUEM5blBqeG5JR2xrUFNKd1lYSjBhV0ZzVEdWaFpsQnNiM1FpUGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNCc2IzUWlJSGc5SWkwek5TSWdlVDBpTUNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUTTFJaUI1UFNJd0lpQm1hV3hzUFNJalFUaERPRE5CSWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4TDJjK1BHY2dhV1E5SW14bFlXWWlQanh3WVhSb0lHUTlJazB4TnpFdU9EZzBJREV4T0M0NU9ETmhOQzQ1TXpJZ05DNDVNeklnTUNBd0lERXRNUzR3TVRnZ01pNDJNRFlnTkM0M01UVWdOQzQzTVRVZ01DQXdJREV0TVM0NE56Z2dNUzQwTXpsakxTNDBOalV1TVRrMUxURXVOek0xTGpjeU55MHlMak0yTkM0eE56WXRMakkwTmlBekxqSTVPQzB4TGpVNU15QTJMalV4TWkweUxqSTFNeUEzTGprMU5HRTBMalV6TWlBMExqVXpNaUF3SURBZ01TMHVNekV6TFM0NU16TmpMUzR5TVRFdExqazNOUzB1TURNNExURXVOell6TGpBM09DMHlMakk1TlM0eU1ESXRMamt5TVM0ek5UTXRNUzQyTVRJdU5EWTNMVEl1TVRRdE1TNHhOemN1TmprMExUSXVOalF5TGpVMk9TMHpMalUxT0MwdU1qY3lMUzQzT1RZdExqY3pNaTB4TGpBNE15MHhMamt5TVMwdU56UXpMVE11TURNMExqUTVPQzR3TVRFZ01TNDVNemt1TVRBNUlETXVNalEzSURFdU1UWTNZVFV1TVRNZ05TNHhNeUF3SURBZ01TQXhMakl4SURFdU5ERXpZeTR4TlRrdExqYzBMakU1T1MwdU9UVTRMakl6T0MweExqRTNPUzR5TURrdE1TNHlNVE11TXpJeUxURXVPRGN5TGpJM05DMHlMamN5TkdFM0xqY3pJRGN1TnpNZ01DQXdJREF0TGprd09DMHpMakUzTjJNdExqYzNNaTQwTVRVdE1TNDNPRGt1TVRrMkxUSXVNemM0TFM0ek1EUXRMak16T1MwdU1qZzNMUzQxTlRZdExqWTRNaTB1TnpZMExURXVOamt5WVRFeUxqY3pPU0F4TWk0M016a2dNQ0F3SURFdExqRTNOaTB6TGprd09XTXVOemc1TGpZd015QXhMalEzSURFdU1ERTVJREV1T1RNM0lERXVNamd6TGprME5DNDFNellnTVM0ek5EUXVOak01SURFdU56WXhJREV1TVRZM0xqRTFNaTR4T1RNdU5qUTVMamcwTWk0MU9EWWdNUzQzTlRFdExqQXhNUzR4TnpJdExqQTFNeTQzT1RVdExqUTJOQ0F4TGpJNU0yRTJMamd6SURZdU9ETWdNQ0F3SURFZ01TNHpPRFFnTWk0eU1qZGpMakUwTGpNMk9DNHlOREl1TnpRMExqTXhNU0F4TGpFMUxqRXdOeTB1TWpBM0xqSTJNUzB1TkRNNUxqVXhNUzB1TnpJeUxqUTFNeTB1TlRFekxqZzNMUzQ1T1RJZ01TNDJNRFF0TVM0eU9EUXVOamd6TFM0eU56SWdNUzR5T0MwdU1qUTVJREV1TnpJekxTNHlNelJoTlM0ek1ESWdOUzR6TURJZ01DQXdJREVnTVM0ME9EWXVNamN6V2lJdlBqd3ZaejQ4WnlCcFpEMGljMmxzYnlJK1BIQmhkR2dnWkQwaVRUVTNMakV3T0NBM01TNHlPV011TVRnNExURXhMalkxTXkweE1pNHdNUzB5TVM0ek1ETXRNamN1TWpRekxUSXhMalUxTWkweE5TNHlNelF0TGpJMUxUSTNMamN6TmlBNExqazVOUzB5Tnk0NU1qTWdNakF1TmpRNUxTNHhPRGNnTVRFdU5qVTBJREV5TGpBeElESXhMak13TkNBeU55NHlORFFnTWpFdU5UVXpJREUxTGpJek15NHlOU0F5Tnk0M016VXRPQzQ1T1RVZ01qY3VPVEl5TFRJd0xqWTFXaUlnWm1sc2JEMGlJelkyTmlJdlBqeHdZWFJvSUdROUlrMHVORFkwSURFNUxqVTBOR011TmprNUlERTJMalU0TlNBeExqUWdNek11TVRZNUlESXVNRGs0SURRNUxqYzFNaTR3TWpFZ01pNHpPREV1TkRnZ05DNHlOemd1T0RneklEVXVOVE01TGpJM055NDROaTQzTkRFZ01pNHlOelVnTVM0M056Z2dNeTQ0TmpjdU5EazBMamMxT1NBeExqSXhNaUF4TGpjZ015NHdNRElnTXk0ek16SWdNUzQzTXprZ01TNDFPRFlnTXk0ek5TQXpMakExTmlBMUxqY3pNaUEwTGpNNU9DQXpMakk1TXlBeExqZzFOU0EyTGpFMU1TQXlMak01TmlBNExqYzVNU0F5TGpnNU5pQXhMamcxTlM0ek5TQTFMakUwT1M0NU5EZ2dPUzQwT0RndU5UVTJZVE15TGpjd055QXpNaTQzTURjZ01DQXdJREFnT1M0ek1UVXRNaTR5T0Rkak1TNDROakl0TGpjMU9TQTBMalkwTWkweExqa3hOeUEzTGpZek15MDBMalFnTVM0ek5EZ3RNUzR4TWlBekxqUTBPQzB5TGpnNU55QTFMakU1TnkwMUxqazFZVEl3TGpFeE5DQXlNQzR4TVRRZ01DQXdJREFnTWk0eU5TMDFMams1T0dNdU1qRXRNVGN1TlRVeUxqUXlMVE0xTGpFd05DNDJNekl0TlRJdU5qVTNiQzAxTmk0NExqazFNbWd1TURBeFdpSWdabWxzYkQwaUkwSXpRak5DTXlJdlBqeHdZWFJvSUdROUlrMDFOeTQwT0NBeE9TNDBPREpETlRjdU5qUTFJRGt1TWpRZ05EUXVPVGM0TGpjeU55QXlPUzR4T0RjdU5EWTRJREV6TGpNNU55NHlNUzQwTmpNZ09DNHpNRE11TWprNElERTRMalUwTmk0eE16UWdNamd1TnpnNElERXlMamdnTXpjdU15QXlPQzQxT1RFZ016Y3VOVFpqTVRVdU56a3VNalU0SURJNExqY3lOQzAzTGpnek5TQXlPQzQ0T0RrdE1UZ3VNRGM0V2lJZ1ptbHNiRDBpSTBORFF5SXZQanh3WVhSb0lHUTlJazB6TUM0ek1UUWdOeTR4TXpkakxqQXdPUzB1TlRZeExTNDJPQzB4TGpBeU9DMHhMalV6T0MweExqQTBNaTB1T0RVNUxTNHdNVFF0TVM0MU5qSXVORE10TVM0MU56RXVPVGt4TFM0d01TNDFOakl1TmpnZ01TNHdNamdnTVM0MU16Z2dNUzR3TkRJdU9EVTVMakF4TlNBeExqVTJNaTB1TkRNZ01TNDFOeTB1T1RsYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFRZdU5ERTBJREk0TGpnNVlURTFMamMzTnlBeE5TNDNOemNnTUNBd0lERXRNaTR3T1RNdE1pNHhORFpqTFM0NE5UWXRNUzR3TmpNdE1pNDBOVE10TXk0d09UTXRNaTQ1TnpVdE5pNHhNVEpoTVRFdU56WTFJREV4TGpjMk5TQXdJREFnTVMwdU1Ea3pMVE11TXpBM2JESTFMalF6TFRrdU9UYzJZeTR3TkRNdU1UUXlMakU0T0M0MU5UVXVOakEwTGpnMk9DNDBOaTR6TkRZdU9UUTNMak0wSURFdU1EZzJMak16TkV3MkxqUXhNeUF5T0M0NE9EaDJMakF3TWxvaUlHWnBiR3c5SWlORk5rVTJSVFlpTHo0OGNHRjBhQ0J2Y0dGamFYUjVQU0l1TXpNaUlHUTlJazB4TGpRM055QXhOaTR3TWpsakxqSTFMUzQ1TXpFdU56QTJMVEl1TWpVNElERXVOVGN0TXk0Mk9UVXVOalUxTFRFdU1Ea3lJREV1TWpreUxURXVPREkxSURFdU56WXRNaTR6TlRndU5UZzBMUzQyTmpVZ01TNDNOell0TVM0NU16UWdNeTQyTnprdE15NHlPU0F5TGprMU15MHlMakV3TlNBMUxqWTVOaTB6TGpBMUlEY3VOekl6TFRNdU56TmhNemN1TXpVZ016Y3VNelVnTUNBd0lERWdOaTQwT0RVdE1TNDFORGRzTlM0eU5ESWdOQzR6TVRaaE1TNDBPQ0F4TGpRNElEQWdNQ0F3TFRFdU1qRTBMamsyTjB3eExqUTRJREUyTGpBemFDMHVNREF5V2lJZ1ptbHNiRDBpSXprNU9TSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNDBOQ0lnWkQwaVRURXVPREVnTWpZdU5UTXlZeTR5TURZdU5EazBMalE0TkNBeExqQTFMamcySURFdU5qTmhNVEF1TWpZMklERXdMakkyTmlBd0lEQWdNQ0F5TGpJM09DQXlMalE0Tmt3MkxqVTFNaUEzT0M0eU1tRXhOeTR5TnpJZ01UY3VNamN5SURBZ01DQXhMVE10Tnk0ME1UTk1NUzQ0TVNBeU5pNDFNekphSWlCbWFXeHNQU0lqUlRaRk5rVTJJaTgrUEhCaGRHZ2daRDBpYlRNekxqQTVNaUEwT1M0ME5ERXROaTR6T0RFZ01UVXVNakV4Y3kwMkxqQTNPQzB4TVM0eE5Ua2dOaTR6T0RFdE1UVXVNakZhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEhCaGRHZ2daRDBpYlRJMkxqY3lOU0EyTkM0NE5UZ3RMakE1TVMwdU1UYzFZeTB1TURJMkxTNHdORGt0TWk0Mk16UXROQzQ1TWpNdExqZzJOeTA1TGpNM0lERXVNRFUzTFRJdU56RTNJRE11TlRFNExUUXVOekkxSURjdU15MDFMamswTm13dU1UZzNMUzR3TmpFdE5pNDFNeUF4TlM0MU5USmFiVFl1TWpFeUxURTFMakkyT0dNdE15NDJNakVnTVM0eU1UY3ROUzQ1T1RFZ015NHhOamd0Tnk0d01qSWdOUzQzT1RndE1TNDFNemdnTXk0NU1EZ3VNelUxSURndU1UWTJMamM0T0NBNUxqQTFOR3cyTGpJek5DMHhOQzQ0TlRKYVRUSTRMakE1TXlBMk15NDNNemRzTkM0ME9EUXRNVEF1T0Rkek55NHpOalVnTmk0ek16Y3ROQzQwT0RRZ01UQXVPRGRhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEM5blBqeG5JR2xrUFNKQ1JVRk9JajQ4Y21WamRDQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnM0lERXVNalkxTFRNdU5UQTBJRGt1TXpaVExqSTVPQ0F6TGprNU9TQTNMalk0TnlBeExqSTJObHB0TFRJdU5qa3hJRGd1TnpnZ01pNDBOakl0Tmk0Mk9URnpOQzQxTXpnZ015NDJOeTB5TGpRMk1pQTJMalk1TVZvaUlHWnBiR3c5SWlObVptWWlMejQ4TDJjK1BHY2dhV1E5SWtKRlFVNHpRMUpXSWo0OGNtVmpkQ0I1UFNJdU5TSWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE55QXhMamMyTkMwekxqVXdOQ0E1TGpNMlV5NHlPVGdnTkM0ME9Ua2dOeTQyT0RjZ01TNDNOalZhSWlCbWFXeHNQU0lqWm1abUlpOCtQSEJoZEdnZ1pEMGlUVGd1TVRNeUlEZ3VNRGM0WXkwdU5EWTJMalkwTFRFdU1qazNJREV1TXpJekxUSXVOamsxSURFdU9Ua3liREl1TVRJMkxUVXVOemMzWXk0d09Ea3VNRGt1TVRrekxqSXdOQzR6TGpNek9DNHpNRE11TXpjMUxqWXlOUzQ0T1RFdU56UTBJREV1TkRnMExqRXhOeTQxT0RNdU1EUWdNUzR5TlRNdExqUTNOU0F4TGprMk0xb2lJR1pwYkd3OUluVnliQ2dqWVNraUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMWGRwWkhSb1BTSXVOU0l2UGp4a1pXWnpQanhzYVc1bFlYSkhjbUZrYVdWdWRDQnBaRDBpWVNJZ2VERTlJall1T1RVaUlIa3hQU0l6TGpnMU15SWdlREk5SWpZdU9UVWlJSGt5UFNJeE1DNDFORFFpSUdkeVlXUnBaVzUwVlc1cGRITTlJblZ6WlhKVGNHRmpaVTl1VlhObElqNDhjM1J2Y0NCemRHOXdMV052Ykc5eVBTSWpPREl3TWpBeUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU1UZ3lJaUJ6ZEc5d0xXTnZiRzl5UFNJalJqY3hSVEExSWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TlRFMklpQnpkRzl3TFdOdmJHOXlQU0lqUmpCR05UQTNJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOek0wSWlCemRHOXdMV052Ykc5eVBTSWpPRFZEUkRjMUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeElpQnpkRzl3TFdOdmJHOXlQU0lqTURJNVJFWkNJaTgrUEM5c2FXNWxZWEpIY21Ga2FXVnVkRDQ4TDJSbFpuTStQQzluUGp4bklHbGtQU0oxY2tKRlFVNGlQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RjZ01TNHlOalV0TXk0MU1EUWdPUzR6TmxNdU1qazRJRE11T1RrNUlEY3VOamczSURFdU1qWTJXbTB0TWk0Mk9URWdPQzQzT0NBeUxqUTJNaTAyTGpZNU1YTTBMalV6T0NBekxqWTNMVEl1TkRZeUlEWXVOamt4V2lJZ1ptbHNiRDBpSTJabVppSXZQand2Wno0OFp5QnBaRDBpUWtWQlRrVlVTQ0krUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE5DQXhMakkyTlMwekxqVXdOU0E1TGpNMll5NHdNRE1nTUMwekxqZzROQzAyTGpZeU5TQXpMalV3TlMwNUxqTTJXaUlnWm1sc2JEMGlJMlptWmlJdlBqeHdZWFJvSUdROUlrMDRMamsxTWlBMkxqazRObUV1TURZekxqQTJNeUF3SURBZ01TMHVNREl5TGpBd00yTXRMamN4TGpFekxURXVOREkwTGpJMU5TMHlMakV6TkM0ek9ERXRMakk0TVM0d05USXRMalUyTlM0eE1ETXRMamcwTmk0eE5USmhMakF6Tmk0d016WWdNQ0F3SURFdExqQXlOaUF3YkRJdU1UUXROUzQyTWpVdU1EQTBMUzR3TUROakxqSTVOeUF4TGpjd01pNDFPU0F6TGpNNU5DNDRPRFFnTlM0d09USmFiUzB1TVRnM0xqUTNPR010TVM0eU5qWXVPRFU1TFRJdU5UTXhJREV1TnpJeExUTXVPQ0F5TGpVNGJDNDNPREV0TWk0d05UUmpMakF3Tnk0d01EUXVNREV6SURBZ0xqQXlNeUF3SUM0M05Ua3RMakV6TWlBeExqVXhOQzB1TWpZNElESXVNamN0TGpSc0xqWTVOeTB1TVRJMkxqQXpMUzR3TURaakxTNHdNRFF1TURBeklEQWdMakF3TmlBd0lDNHdNRFphSWlCbWFXeHNQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0oxY2tKRlFVNUZWRWdpUGp4eVpXTjBJSGRwWkhSb1BTSXhNaUlnYUdWcFoyaDBQU0l4TWlJZ2NuZzlJallpSUdacGJHdzlJaU0zUmpVMU16TWlMejQ4Y0dGMGFDQmtQU0p0Tnk0Mk9EUWdNUzR5TmpVdE15NDFNRFVnT1M0ek5tTXVNREF6SURBdE15NDRPRFF0Tmk0Mk1qVWdNeTQxTURVdE9TNHpObG9pSUdacGJHdzlJaU5tWm1ZaUx6NDhjR0YwYUNCa1BTSk5PQzQ1TlRJZ05pNDVPRFpoTGpBMk15NHdOak1nTUNBd0lERXRMakF5TWk0d01ETmpMUzQzTVM0eE15MHhMalF5TkM0eU5UVXRNaTR4TXpRdU16Z3hMUzR5T0RFdU1EVXlMUzQxTmpVdU1UQXpMUzQ0TkRZdU1UVXlZUzR3TXpZdU1ETTJJREFnTUNBeExTNHdNallnTUd3eUxqRTBMVFV1TmpJMUxqQXdOQzB1TURBell5NHlPVGNnTVM0M01ESXVOVGtnTXk0ek9UUXVPRGcwSURVdU1Ea3lXbTB0TGpFNE55NDBOemhqTFRFdU1qWTJMamcxT1MweUxqVXpNU0F4TGpjeU1TMHpMamdnTWk0MU9Hd3VOemd4TFRJdU1EVTBZeTR3TURjdU1EQTBMakF4TXlBd0lDNHdNak1nTUNBdU56VTVMUzR4TXpJZ01TNDFNVFF0TGpJMk9DQXlMakkzTFM0MGJDNDJPVGN0TGpFeU5pNHdNeTB1TURBMll5MHVNREEwTGpBd015QXdJQzR3TURZZ01DQXVNREEyV2lJZ1ptbHNiRDBpSXpBd01DSXZQand2Wno0OFp5QnBaRDBpYkdWaFpsSnZkeUkrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTUNJZ2VUMGlNQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweE1pSWdlVDBpTFRjaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXRNalFpSUhrOUlpMHhOQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkwek5pSWdlVDBpTFRJeElpOCtQQzluUGp3dlpHVm1jejQ4Y21WamRDQjNhV1IwYUQwaU1qVTFJaUJvWldsbmFIUTlJak0xTUNJZ2NuZzlJakV3SWlCbWFXeHNQU0lqTWpVek16STJJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYzJsc2J5SWdlRDBpT1RraUlIazlJalUxSWk4K1BHY2dhV1E5SW1Gc2JGQnNiM1FpSUdOc2FYQXRjR0YwYUQwaWRYSnNLQ05pYjNKa1pYSk5ZWE5yS1NJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTB4TmpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRFMk5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqQWlJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l0TVRJMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJdE9EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSTJPU0lnZVQwaUxUZzBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlMVEV6T0NJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTUNJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM05wYkc4aUlIZzlJalEzSWlCNVBTSTFOU0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpjcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqRXpPQ0lnZVQwaU16WWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXROamtpSUhrOUlqYzJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNCaGNuUnBZV3hNWldGbVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTUNJZ2VUMGlNVEUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTVRVMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJeE5UWWlJQzgrUEM5blBqeHlaV04wSUhnOUlqQWlJSGs5SWpBaUlIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNakFpSUhKNFBTSTFJaUJtYVd4c1BTSWpNalF5TkRJMElpOCtQSFJsZUhRZ2VEMGlNVEFpSUhrOUlqRTBMalVpSUdadmJuUXRjMmw2WlQwaU1USWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGljM1JoY25RaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQblZ5UWtWQlRpQkVaWEJ2YzJsMFBDOTBaWGgwUGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNWeVFrVkJUaUlnZUQwaU1qUXdJaUI1UFNJMElpQXZQanh5WldOMElIZzlJakFpSUhrOUlqTXpNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1qY2lJSGs5SWpNME15SWdabTl1ZEMxemFYcGxQU0l4TUNJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKdGFXUmtiR1VpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBqeDBjM0JoYmo0OFlXNXBiV0YwWlNCaGRIUnlhV0oxZEdWT1lXMWxQU0o0SWlCbWNtOXRQU0l6TnpVaUlIUnZQU0kxTUNJZ1pIVnlQU0l4TUhNaUlISmxjR1ZoZEVOdmRXNTBQU0pwYm1SbFptbHVhWFJsSWlBdlBqQjRNV0psWVRBd05UQmxOak5sTURWbVltSTFaRGhpWVRKbU1UQmpaalU0TURCaU5qSXlORFEwT1R3dmRITndZVzQrUEM5MFpYaDBQangwWlhoMElIZzlJakV5TnlJZ2VUMGlNelF6SWlCbWIyNTBMWE5wZW1VOUlqRXdJaUJtYVd4c1BTSlhhR2wwWlNJZ2RHVjRkQzFoYm1Ob2IzSTlJbTFwWkdSc1pTSWdabTl1ZEMxbVlXMXBiSGs5SW1aMWRIVnlZU0krUEhSemNHRnVQanhoYm1sdFlYUmxJR0YwZEhKcFluVjBaVTVoYldVOUluZ2lJR1p5YjIwOUlqVXdJaUIwYnowaUxUSTNOU0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNE1XSmxZVEF3TlRCbE5qTmxNRFZtWW1JMVpEaGlZVEptTVRCalpqVTRNREJpTmpJeU5EUTBPVHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqSXpOU0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSmxibVFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBsTjBaVzA2SURFd01qUThMM1JsZUhRK1BDOXpkbWMrIn0= \ No newline at end of file diff --git a/protocol/test/data/base64EncodedImageUrBeanEth.txt b/protocol/test/data/base64EncodedImageUrBeanEth.txt index d6be106d40..00e851abe0 100644 --- a/protocol/test/data/base64EncodedImageUrBeanEth.txt +++ b/protocol/test/data/base64EncodedImageUrBeanEth.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IHVyQkVBTkVUSFxuVG9rZW4gQWRkcmVzczogMHgxYmVhM2NjZDIyZjRlYmQzZDM3ZDczMWJhMzFlZWNhOTU3MTM3MTZkXG5JZDogMHgxYmVhM2NjZDIyZjRlYmQzZDM3ZDczMWJhMzFlZWNhOTU3MTM3MTZkZmZmZmZmZmZmZmZmZmZmZmZmZmZmOTdjXG5zdGVtOiAtMTY2OFxuaW5pdGFsIHN0YWxrIHBlciBCRFY6IDEwMDAwXG5ncm93biBzdGFsayBwZXIgQkRWOiAzNjcwXG5zdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb246IDIwMDAwMDBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCamJHRnpjejBpYzNablFtOWtlU0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJek5UQWlJSFpwWlhkQ2IzZzlJakFnTUNBeU5UVWdNelV3SWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhodGJHNXpPbmhzYVc1clBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJajQ4WkdWbWN6NDhaeUJwWkQwaWNHeHZkQ0krUEhCaGRHZ2daRDBpVFRjNUxqVTNNamdnTVRJNUxqSTJOVXd4TWpjdU5EWTVJREUxTmk0NE16Tk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UQXhMalk1TjB3M09TNDFOekk0SURFeU9TNHlOalZhSWlCbWFXeHNQU0lqT1RRMFFUSTNJaTgrUEhCaGRHZ2daRDBpVFRjNUxqVXpNeklnTVRNekxqUXlOa3czT1M0MU56STNJREV5T1M0eU5qVk1NVEkzTGpRMk9TQXhOVFl1T0RNelRERXlOeTQxTURjZ01UWXdMamt3T0V3M09TNDFNek15SURFek15NDBNalphSWlCbWFXeHNQU0lqTnpVek9URkdJaTgrUEhCaGRHZ2daRDBpVFRFM05TNDBOamNnTVRNekxqUk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UVTJMamd6TTB3eE1qY3VOVEEzSURFMk1DNDVNRGhNTVRjMUxqUTJOeUF4TXpNdU5Gb2lJR1pwYkd3OUlpTTJOek16TVVVaUx6NDhMMmMrUEdjZ2FXUTlJbVoxYkd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUWXdJaUI1UFNJeE5DSWdabWxzYkQwaUkwRTRRemd6UVNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUY3pJaUI1UFNJeU1TSWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKbGJYQjBlVkJzYjNRaVBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQnNiM1FpSUhnOUlpMHpOU0lnZVQwaU1DSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSndZWEowYVdGc1RHVmhabEp2ZHlJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaU1DSWdlVDBpTUNJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1lpSUhnOUlpMHhNaUlnZVQwaUxUY2lMejQ4TDJjK1BHY2dhV1E5SW5CaGNuUnBZV3hNWldGbVVHeHZkQ0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0d4dmRDSWdlRDBpTFRNMUlpQjVQU0l3SWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU53WVhKMGFXRnNUR1ZoWmxKdmR5SWdlRDBpTFRNMUlpQjVQU0l3SWlCbWFXeHNQU0lqUVRoRE9ETkJJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhMMmMrUEdjZ2FXUTlJbXhsWVdZaVBqeHdZWFJvSUdROUlrMHhOekV1T0RnMElERXhPQzQ1T0ROaE5DNDVNeklnTkM0NU16SWdNQ0F3SURFdE1TNHdNVGdnTWk0Mk1EWWdOQzQzTVRVZ05DNDNNVFVnTUNBd0lERXRNUzQ0TnpnZ01TNDBNemxqTFM0ME5qVXVNVGsxTFRFdU56TTFMamN5TnkweUxqTTJOQzR4TnpZdExqSTBOaUF6TGpJNU9DMHhMalU1TXlBMkxqVXhNaTB5TGpJMU15QTNMamsxTkdFMExqVXpNaUEwTGpVek1pQXdJREFnTVMwdU16RXpMUzQ1TXpOakxTNHlNVEV0TGprM05TMHVNRE00TFRFdU56WXpMakEzT0MweUxqSTVOUzR5TURJdExqa3lNUzR6TlRNdE1TNDJNVEl1TkRZM0xUSXVNVFF0TVM0eE56Y3VOamswTFRJdU5qUXlMalUyT1MwekxqVTFPQzB1TWpjeUxTNDNPVFl0TGpjek1pMHhMakE0TXkweExqa3lNUzB1TnpRekxUTXVNRE0wTGpRNU9DNHdNVEVnTVM0NU16a3VNVEE1SURNdU1qUTNJREV1TVRZM1lUVXVNVE1nTlM0eE15QXdJREFnTVNBeExqSXhJREV1TkRFell5NHhOVGt0TGpjMExqRTVPUzB1T1RVNExqSXpPQzB4TGpFM09TNHlNRGt0TVM0eU1UTXVNekl5TFRFdU9EY3lMakkzTkMweUxqY3lOR0UzTGpjeklEY3VOek1nTUNBd0lEQXRMamt3T0MwekxqRTNOMk10TGpjM01pNDBNVFV0TVM0M09Ea3VNVGsyTFRJdU16YzRMUzR6TURRdExqTXpPUzB1TWpnM0xTNDFOVFl0TGpZNE1pMHVOelkwTFRFdU5qa3lZVEV5TGpjek9TQXhNaTQzTXprZ01DQXdJREV0TGpFM05pMHpMamt3T1dNdU56ZzVMall3TXlBeExqUTNJREV1TURFNUlERXVPVE0zSURFdU1qZ3pMamswTkM0MU16WWdNUzR6TkRRdU5qTTVJREV1TnpZeElERXVNVFkzTGpFMU1pNHhPVE11TmpRNUxqZzBNaTQxT0RZZ01TNDNOVEV0TGpBeE1TNHhOekl0TGpBMU15NDNPVFV0TGpRMk5DQXhMakk1TTJFMkxqZ3pJRFl1T0RNZ01DQXdJREVnTVM0ek9EUWdNaTR5TWpkakxqRTBMak0yT0M0eU5ESXVOelEwTGpNeE1TQXhMakUxTGpFd055MHVNakEzTGpJMk1TMHVORE01TGpVeE1TMHVOekl5TGpRMU15MHVOVEV6TGpnM0xTNDVPVElnTVM0Mk1EUXRNUzR5T0RRdU5qZ3pMUzR5TnpJZ01TNHlPQzB1TWpRNUlERXVOekl6TFM0eU16UmhOUzR6TURJZ05TNHpNRElnTUNBd0lERWdNUzQwT0RZdU1qY3pXaUl2UGp3dlp6NDhaeUJwWkQwaWMybHNieUkrUEhCaGRHZ2daRDBpVFRVM0xqRXdPQ0EzTVM0eU9XTXVNVGc0TFRFeExqWTFNeTB4TWk0d01TMHlNUzR6TURNdE1qY3VNalF6TFRJeExqVTFNaTB4TlM0eU16UXRMakkxTFRJM0xqY3pOaUE0TGprNU5TMHlOeTQ1TWpNZ01qQXVOalE1TFM0eE9EY2dNVEV1TmpVMElERXlMakF4SURJeExqTXdOQ0F5Tnk0eU5EUWdNakV1TlRVeklERTFMakl6TXk0eU5TQXlOeTQzTXpVdE9DNDVPVFVnTWpjdU9USXlMVEl3TGpZMVdpSWdabWxzYkQwaUl6WTJOaUl2UGp4d1lYUm9JR1E5SWswdU5EWTBJREU1TGpVME5HTXVOams1SURFMkxqVTROU0F4TGpRZ016TXVNVFk1SURJdU1EazRJRFE1TGpjMU1pNHdNakVnTWk0ek9ERXVORGdnTkM0eU56Z3VPRGd6SURVdU5UTTVMakkzTnk0NE5pNDNOREVnTWk0eU56VWdNUzQzTnpnZ015NDROamN1TkRrMExqYzFPU0F4TGpJeE1pQXhMamNnTXk0d01ESWdNeTR6TXpJZ01TNDNNemtnTVM0MU9EWWdNeTR6TlNBekxqQTFOaUExTGpjek1pQTBMak01T0NBekxqSTVNeUF4TGpnMU5TQTJMakUxTVNBeUxqTTVOaUE0TGpjNU1TQXlMamc1TmlBeExqZzFOUzR6TlNBMUxqRTBPUzQ1TkRnZ09TNDBPRGd1TlRVMllUTXlMamN3TnlBek1pNDNNRGNnTUNBd0lEQWdPUzR6TVRVdE1pNHlPRGRqTVM0NE5qSXRMamMxT1NBMExqWTBNaTB4TGpreE55QTNMall6TXkwMExqUWdNUzR6TkRndE1TNHhNaUF6TGpRME9DMHlMamc1TnlBMUxqRTVOeTAxTGprMVlUSXdMakV4TkNBeU1DNHhNVFFnTUNBd0lEQWdNaTR5TlMwMUxqazVPR011TWpFdE1UY3VOVFV5TGpReUxUTTFMakV3TkM0Mk16SXROVEl1TmpVM2JDMDFOaTQ0TGprMU1tZ3VNREF4V2lJZ1ptbHNiRDBpSTBJelFqTkNNeUl2UGp4d1lYUm9JR1E5SWswMU55NDBPQ0F4T1M0ME9ESkROVGN1TmpRMUlEa3VNalFnTkRRdU9UYzRMamN5TnlBeU9TNHhPRGN1TkRZNElERXpMak01Tnk0eU1TNDBOak1nT0M0ek1ETXVNams0SURFNExqVTBOaTR4TXpRZ01qZ3VOemc0SURFeUxqZ2dNemN1TXlBeU9DNDFPVEVnTXpjdU5UWmpNVFV1TnprdU1qVTRJREk0TGpjeU5DMDNMamd6TlNBeU9DNDRPRGt0TVRndU1EYzRXaUlnWm1sc2JEMGlJME5EUXlJdlBqeHdZWFJvSUdROUlrMHpNQzR6TVRRZ055NHhNemRqTGpBd09TMHVOVFl4TFM0Mk9DMHhMakF5T0MweExqVXpPQzB4TGpBME1pMHVPRFU1TFM0d01UUXRNUzQxTmpJdU5ETXRNUzQxTnpFdU9Ua3hMUzR3TVM0MU5qSXVOamdnTVM0d01qZ2dNUzQxTXpnZ01TNHdOREl1T0RVNUxqQXhOU0F4TGpVMk1pMHVORE1nTVM0MU55MHVPVGxhSWlCbWFXeHNQU0lqTmpZMklpOCtQSEJoZEdnZ1pEMGlUVFl1TkRFMElESTRMamc1WVRFMUxqYzNOeUF4TlM0M056Y2dNQ0F3SURFdE1pNHdPVE10TWk0eE5EWmpMUzQ0TlRZdE1TNHdOak10TWk0ME5UTXRNeTR3T1RNdE1pNDVOelV0Tmk0eE1USmhNVEV1TnpZMUlERXhMamMyTlNBd0lEQWdNUzB1TURrekxUTXVNekEzYkRJMUxqUXpMVGt1T1RjMll5NHdORE11TVRReUxqRTRPQzQxTlRVdU5qQTBMamcyT0M0ME5pNHpORFl1T1RRM0xqTTBJREV1TURnMkxqTXpORXcyTGpReE15QXlPQzQ0T0RoMkxqQXdNbG9pSUdacGJHdzlJaU5GTmtVMlJUWWlMejQ4Y0dGMGFDQnZjR0ZqYVhSNVBTSXVNek1pSUdROUlrMHhMalEzTnlBeE5pNHdNamxqTGpJMUxTNDVNekV1TnpBMkxUSXVNalU0SURFdU5UY3RNeTQyT1RVdU5qVTFMVEV1TURreUlERXVNamt5TFRFdU9ESTFJREV1TnpZdE1pNHpOVGd1TlRnMExTNDJOalVnTVM0M056WXRNUzQ1TXpRZ015NDJOemt0TXk0eU9TQXlMamsxTXkweUxqRXdOU0ExTGpZNU5pMHpMakExSURjdU56SXpMVE11TnpOaE16Y3VNelVnTXpjdU16VWdNQ0F3SURFZ05pNDBPRFV0TVM0MU5EZHNOUzR5TkRJZ05DNHpNVFpoTVM0ME9DQXhMalE0SURBZ01DQXdMVEV1TWpFMExqazJOMHd4TGpRNElERTJMakF6YUMwdU1EQXlXaUlnWm1sc2JEMGlJems1T1NJdlBqeHdZWFJvSUc5d1lXTnBkSGs5SWk0ME5DSWdaRDBpVFRFdU9ERWdNall1TlRNeVl5NHlNRFl1TkRrMExqUTROQ0F4TGpBMUxqZzJJREV1TmpOaE1UQXVNalkySURFd0xqSTJOaUF3SURBZ01DQXlMakkzT0NBeUxqUTROa3cyTGpVMU1pQTNPQzR5TW1FeE55NHlOeklnTVRjdU1qY3lJREFnTUNBeExUTXROeTQwTVROTU1TNDRNU0F5Tmk0MU16SmFJaUJtYVd4c1BTSWpSVFpGTmtVMklpOCtQSEJoZEdnZ1pEMGliVE16TGpBNU1pQTBPUzQwTkRFdE5pNHpPREVnTVRVdU1qRXhjeTAyTGpBM09DMHhNUzR4TlRrZ05pNHpPREV0TVRVdU1qRmFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQSEJoZEdnZ1pEMGliVEkyTGpjeU5TQTJOQzQ0TlRndExqQTVNUzB1TVRjMVl5MHVNREkyTFM0d05Ea3RNaTQyTXpRdE5DNDVNak10TGpnMk55MDVMak0zSURFdU1EVTNMVEl1TnpFM0lETXVOVEU0TFRRdU56STFJRGN1TXkwMUxqazBObXd1TVRnM0xTNHdOakV0Tmk0MU15QXhOUzQxTlRKYWJUWXVNakV5TFRFMUxqSTJPR010TXk0Mk1qRWdNUzR5TVRjdE5TNDVPVEVnTXk0eE5qZ3ROeTR3TWpJZ05TNDNPVGd0TVM0MU16Z2dNeTQ1TURndU16VTFJRGd1TVRZMkxqYzRPQ0E1TGpBMU5HdzJMakl6TkMweE5DNDROVEphVFRJNExqQTVNeUEyTXk0M016ZHNOQzQwT0RRdE1UQXVPRGR6Tnk0ek5qVWdOaTR6TXpjdE5DNDBPRFFnTVRBdU9EZGFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQQzluUGp4bklHbGtQU0pDUlVGT0lqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU1qWTFMVE11TlRBMElEa3VNelpUTGpJNU9DQXpMams1T1NBM0xqWTROeUF4TGpJMk5scHRMVEl1TmpreElEZ3VOemdnTWk0ME5qSXROaTQyT1RGek5DNDFNemdnTXk0Mk55MHlMalEyTWlBMkxqWTVNVm9pSUdacGJHdzlJaU5tWm1ZaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0elExSldJajQ4Y21WamRDQjVQU0l1TlNJZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TnlBeExqYzJOQzB6TGpVd05DQTVMak0yVXk0eU9UZ2dOQzQwT1RrZ055NDJPRGNnTVM0M05qVmFJaUJtYVd4c1BTSWpabVptSWk4K1BIQmhkR2dnWkQwaVRUZ3VNVE15SURndU1EYzRZeTB1TkRZMkxqWTBMVEV1TWprM0lERXVNekl6TFRJdU5qazFJREV1T1RreWJESXVNVEkyTFRVdU56YzNZeTR3T0RrdU1Ea3VNVGt6TGpJd05DNHpMak16T0M0ek1ETXVNemMxTGpZeU5TNDRPVEV1TnpRMElERXVORGcwTGpFeE55NDFPRE11TURRZ01TNHlOVE10TGpRM05TQXhMamsyTTFvaUlHWnBiR3c5SW5WeWJDZ2pZU2tpSUhOMGNtOXJaVDBpSTJabVppSWdjM1J5YjJ0bExYZHBaSFJvUFNJdU5TSXZQanhrWldaelBqeHNhVzVsWVhKSGNtRmthV1Z1ZENCcFpEMGlZU0lnZURFOUlqWXVPVFVpSUhreFBTSXpMamcxTXlJZ2VESTlJall1T1RVaUlIa3lQU0l4TUM0MU5EUWlJR2R5WVdScFpXNTBWVzVwZEhNOUluVnpaWEpUY0dGalpVOXVWWE5sSWo0OGMzUnZjQ0J6ZEc5d0xXTnZiRzl5UFNJak9ESXdNakF5SWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TVRneUlpQnpkRzl3TFdOdmJHOXlQU0lqUmpjeFJUQTFJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOVEUySWlCemRHOXdMV052Ykc5eVBTSWpSakJHTlRBM0lpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU56TTBJaUJ6ZEc5d0xXTnZiRzl5UFNJak9EVkRSRGMxSWk4K1BITjBiM0FnYjJabWMyVjBQU0l4SWlCemRHOXdMV052Ykc5eVBTSWpNREk1UkVaQ0lpOCtQQzlzYVc1bFlYSkhjbUZrYVdWdWRENDhMMlJsWm5NK1BDOW5QanhuSUdsa1BTSjFja0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNM1JqVTFNek1pTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSjFja0pGUVU1RlZFZ2lQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RRZ01TNHlOalV0TXk0MU1EVWdPUzR6Tm1NdU1EQXpJREF0TXk0NE9EUXROaTQyTWpVZ015NDFNRFV0T1M0ek5sb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNDVOVElnTmk0NU9EWmhMakEyTXk0d05qTWdNQ0F3SURFdExqQXlNaTR3TUROakxTNDNNUzR4TXkweExqUXlOQzR5TlRVdE1pNHhNelF1TXpneExTNHlPREV1TURVeUxTNDFOalV1TVRBekxTNDRORFl1TVRVeVlTNHdNell1TURNMklEQWdNQ0F4TFM0d01qWWdNR3d5TGpFMExUVXVOakkxTGpBd05DMHVNREF6WXk0eU9UY2dNUzQzTURJdU5Ua2dNeTR6T1RRdU9EZzBJRFV1TURreVdtMHRMakU0Tnk0ME56aGpMVEV1TWpZMkxqZzFPUzB5TGpVek1TQXhMamN5TVMwekxqZ2dNaTQxT0d3dU56Z3hMVEl1TURVMFl5NHdNRGN1TURBMExqQXhNeUF3SUM0d01qTWdNQ0F1TnpVNUxTNHhNeklnTVM0MU1UUXRMakkyT0NBeUxqSTNMUzQwYkM0Mk9UY3RMakV5Tmk0d015MHVNREEyWXkwdU1EQTBMakF3TXlBd0lDNHdNRFlnTUNBdU1EQTJXaUlnWm1sc2JEMGlJekF3TUNJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1JaUI0UFNJdE1qUWlJSGs5SWkweE5DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB6TmlJZ2VUMGlMVEl4SWk4K1BDOW5Qand2WkdWbWN6NDhjbVZqZENCM2FXUjBhRDBpTWpVMUlpQm9aV2xuYUhROUlqTTFNQ0lnY25nOUlqRXdJaUJtYVd4c1BTSWpNalV6TXpJMklpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjMmxzYnlJZ2VEMGlPVGtpSUhrOUlqVTFJaTgrUEdjZ2FXUTlJbUZzYkZCc2IzUWlJR05zYVhBdGNHRjBhRDBpZFhKc0tDTmliM0prWlhKTllYTnJLU0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXROamtpSUhrOUlpMHhOalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVEUyTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpBaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJeE16Z2lJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXRNVEkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRnMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNVE00SWlCNVBTSXRORFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzTnBiRzhpSUhnOUlqUTNJaUI1UFNJMU5TSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMamNwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l6TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTndZWEowYVdGc1RHVmhabEJzYjNRaUlIZzlJakV6T0NJZ2VUMGlNellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJamMySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTUNJZ2VUMGlNVEUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTVRVMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJeE5UWWlJQzgrUEM5blBqeHlaV04wSUhnOUlqQWlJSGs5SWpBaUlIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNakFpSUhKNFBTSTFJaUJtYVd4c1BTSWpNalF5TkRJMElpOCtQSFJsZUhRZ2VEMGlNVEFpSUhrOUlqRTBMalVpSUdadmJuUXRjMmw2WlQwaU1USWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGljM1JoY25RaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQblZ5UWtWQlRrVlVTQ0JFWlhCdmMybDBQQzkwWlhoMFBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzVnlRa1ZCVGtWVVNDSWdlRDBpTWpRd0lpQjVQU0kwSWlBdlBqeHlaV04wSUhnOUlqQWlJSGs5SWpNek1DSWdkMmxrZEdnOUlqSTFOU0lnYUdWcFoyaDBQU0l5TUNJZ2NuZzlJalVpSUdacGJHdzlJaU15TkRJME1qUWlMejQ4ZEdWNGRDQjRQU0l4TWpjaUlIazlJak0wTXlJZ1ptOXVkQzF6YVhwbFBTSXhNQ0lnWm1sc2JEMGlWMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0p0YVdSa2JHVWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGp4MGMzQmhiajQ4WVc1cGJXRjBaU0JoZEhSeWFXSjFkR1ZPWVcxbFBTSjRJaUJtY205dFBTSXpOelVpSUhSdlBTSTFNQ0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNE1XSmxZVE5qWTJReU1tWTBaV0prTTJRek4yUTNNekZpWVRNeFpXVmpZVGsxTnpFek56RTJaRHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqRXlOeUlnZVQwaU16UXpJaUJtYjI1MExYTnBlbVU5SWpFd0lpQm1hV3hzUFNKWGFHbDBaU0lnZEdWNGRDMWhibU5vYjNJOUltMXBaR1JzWlNJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStQSFJ6Y0dGdVBqeGhibWx0WVhSbElHRjBkSEpwWW5WMFpVNWhiV1U5SW5naUlHWnliMjA5SWpVd0lpQjBiejBpTFRJM05TSWdaSFZ5UFNJeE1ITWlJSEpsY0dWaGRFTnZkVzUwUFNKcGJtUmxabWx1YVhSbElpQXZQakI0TVdKbFlUTmpZMlF5TW1ZMFpXSmtNMlF6TjJRM016RmlZVE14WldWallUazFOekV6TnpFMlpEd3ZkSE53WVc0K1BDOTBaWGgwUGp4MFpYaDBJSGc5SWpJek5TSWdlVDBpTVRRdU5TSWdabTl1ZEMxemFYcGxQU0l4TWlJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKbGJtUWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGxOMFpXMDZJQzB4TmpZNFBDOTBaWGgwUGp3dmMzWm5QZz09In0= \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJ1ckJFQU5FVEgifSwgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiBBZGRyZXNzIiwgInZhbHVlIjogIjB4MWJlYTNjY2QyMmY0ZWJkM2QzN2Q3MzFiYTMxZWVjYTk1NzEzNzE2ZCJ9LCB7ICJ0cmFpdF90eXBlIjogIklkIiwgInZhbHVlIjogIjB4MWJlYTNjY2QyMmY0ZWJkM2QzN2Q3MzFiYTMxZWVjYTk1NzEzNzE2ZGZmZmZmZmZmZmZmZmZmZmZmZmZmZjk3YyJ9LCB7ICJ0cmFpdF90eXBlIjogInN0ZW0iLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IC0xNjY4fSwgeyAidHJhaXRfdHlwZSI6ICJpbml0YWwgc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMTAwMDB9LCB7ICJ0cmFpdF90eXBlIjogImdyb3duIHN0YWxrIHBlciBCRFYiLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDM2NzB9LCB7ICJ0cmFpdF90eXBlIjogInN0YWxrIGdyb3duIHBlciBCRFYgcGVyIHNlYXNvbiIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMjAwMDAwMCwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OEwyYytQR2NnYVdROUluQmhjblJwWVd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOd1lYSjBhV0ZzVEdWaFpsSnZkeUlnZUQwaUxUTTFJaUI1UFNJd0lpQm1hV3hzUFNJalFUaERPRE5CSWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4TDJjK1BHY2dhV1E5SW14bFlXWWlQanh3WVhSb0lHUTlJazB4TnpFdU9EZzBJREV4T0M0NU9ETmhOQzQ1TXpJZ05DNDVNeklnTUNBd0lERXRNUzR3TVRnZ01pNDJNRFlnTkM0M01UVWdOQzQzTVRVZ01DQXdJREV0TVM0NE56Z2dNUzQwTXpsakxTNDBOalV1TVRrMUxURXVOek0xTGpjeU55MHlMak0yTkM0eE56WXRMakkwTmlBekxqSTVPQzB4TGpVNU15QTJMalV4TWkweUxqSTFNeUEzTGprMU5HRTBMalV6TWlBMExqVXpNaUF3SURBZ01TMHVNekV6TFM0NU16TmpMUzR5TVRFdExqazNOUzB1TURNNExURXVOell6TGpBM09DMHlMakk1TlM0eU1ESXRMamt5TVM0ek5UTXRNUzQyTVRJdU5EWTNMVEl1TVRRdE1TNHhOemN1TmprMExUSXVOalF5TGpVMk9TMHpMalUxT0MwdU1qY3lMUzQzT1RZdExqY3pNaTB4TGpBNE15MHhMamt5TVMwdU56UXpMVE11TURNMExqUTVPQzR3TVRFZ01TNDVNemt1TVRBNUlETXVNalEzSURFdU1UWTNZVFV1TVRNZ05TNHhNeUF3SURBZ01TQXhMakl4SURFdU5ERXpZeTR4TlRrdExqYzBMakU1T1MwdU9UVTRMakl6T0MweExqRTNPUzR5TURrdE1TNHlNVE11TXpJeUxURXVPRGN5TGpJM05DMHlMamN5TkdFM0xqY3pJRGN1TnpNZ01DQXdJREF0TGprd09DMHpMakUzTjJNdExqYzNNaTQwTVRVdE1TNDNPRGt1TVRrMkxUSXVNemM0TFM0ek1EUXRMak16T1MwdU1qZzNMUzQxTlRZdExqWTRNaTB1TnpZMExURXVOamt5WVRFeUxqY3pPU0F4TWk0M016a2dNQ0F3SURFdExqRTNOaTB6TGprd09XTXVOemc1TGpZd015QXhMalEzSURFdU1ERTVJREV1T1RNM0lERXVNamd6TGprME5DNDFNellnTVM0ek5EUXVOak01SURFdU56WXhJREV1TVRZM0xqRTFNaTR4T1RNdU5qUTVMamcwTWk0MU9EWWdNUzQzTlRFdExqQXhNUzR4TnpJdExqQTFNeTQzT1RVdExqUTJOQ0F4TGpJNU0yRTJMamd6SURZdU9ETWdNQ0F3SURFZ01TNHpPRFFnTWk0eU1qZGpMakUwTGpNMk9DNHlOREl1TnpRMExqTXhNU0F4TGpFMUxqRXdOeTB1TWpBM0xqSTJNUzB1TkRNNUxqVXhNUzB1TnpJeUxqUTFNeTB1TlRFekxqZzNMUzQ1T1RJZ01TNDJNRFF0TVM0eU9EUXVOamd6TFM0eU56SWdNUzR5T0MwdU1qUTVJREV1TnpJekxTNHlNelJoTlM0ek1ESWdOUzR6TURJZ01DQXdJREVnTVM0ME9EWXVNamN6V2lJdlBqd3ZaejQ4WnlCcFpEMGljMmxzYnlJK1BIQmhkR2dnWkQwaVRUVTNMakV3T0NBM01TNHlPV011TVRnNExURXhMalkxTXkweE1pNHdNUzB5TVM0ek1ETXRNamN1TWpRekxUSXhMalUxTWkweE5TNHlNelF0TGpJMUxUSTNMamN6TmlBNExqazVOUzB5Tnk0NU1qTWdNakF1TmpRNUxTNHhPRGNnTVRFdU5qVTBJREV5TGpBeElESXhMak13TkNBeU55NHlORFFnTWpFdU5UVXpJREUxTGpJek15NHlOU0F5Tnk0M016VXRPQzQ1T1RVZ01qY3VPVEl5TFRJd0xqWTFXaUlnWm1sc2JEMGlJelkyTmlJdlBqeHdZWFJvSUdROUlrMHVORFkwSURFNUxqVTBOR011TmprNUlERTJMalU0TlNBeExqUWdNek11TVRZNUlESXVNRGs0SURRNUxqYzFNaTR3TWpFZ01pNHpPREV1TkRnZ05DNHlOemd1T0RneklEVXVOVE01TGpJM055NDROaTQzTkRFZ01pNHlOelVnTVM0M056Z2dNeTQ0TmpjdU5EazBMamMxT1NBeExqSXhNaUF4TGpjZ015NHdNRElnTXk0ek16SWdNUzQzTXprZ01TNDFPRFlnTXk0ek5TQXpMakExTmlBMUxqY3pNaUEwTGpNNU9DQXpMakk1TXlBeExqZzFOU0EyTGpFMU1TQXlMak01TmlBNExqYzVNU0F5TGpnNU5pQXhMamcxTlM0ek5TQTFMakUwT1M0NU5EZ2dPUzQwT0RndU5UVTJZVE15TGpjd055QXpNaTQzTURjZ01DQXdJREFnT1M0ek1UVXRNaTR5T0Rkak1TNDROakl0TGpjMU9TQTBMalkwTWkweExqa3hOeUEzTGpZek15MDBMalFnTVM0ek5EZ3RNUzR4TWlBekxqUTBPQzB5TGpnNU55QTFMakU1TnkwMUxqazFZVEl3TGpFeE5DQXlNQzR4TVRRZ01DQXdJREFnTWk0eU5TMDFMams1T0dNdU1qRXRNVGN1TlRVeUxqUXlMVE0xTGpFd05DNDJNekl0TlRJdU5qVTNiQzAxTmk0NExqazFNbWd1TURBeFdpSWdabWxzYkQwaUkwSXpRak5DTXlJdlBqeHdZWFJvSUdROUlrMDFOeTQwT0NBeE9TNDBPREpETlRjdU5qUTFJRGt1TWpRZ05EUXVPVGM0TGpjeU55QXlPUzR4T0RjdU5EWTRJREV6TGpNNU55NHlNUzQwTmpNZ09DNHpNRE11TWprNElERTRMalUwTmk0eE16UWdNamd1TnpnNElERXlMamdnTXpjdU15QXlPQzQxT1RFZ016Y3VOVFpqTVRVdU56a3VNalU0SURJNExqY3lOQzAzTGpnek5TQXlPQzQ0T0RrdE1UZ3VNRGM0V2lJZ1ptbHNiRDBpSTBORFF5SXZQanh3WVhSb0lHUTlJazB6TUM0ek1UUWdOeTR4TXpkakxqQXdPUzB1TlRZeExTNDJPQzB4TGpBeU9DMHhMalV6T0MweExqQTBNaTB1T0RVNUxTNHdNVFF0TVM0MU5qSXVORE10TVM0MU56RXVPVGt4TFM0d01TNDFOakl1TmpnZ01TNHdNamdnTVM0MU16Z2dNUzR3TkRJdU9EVTVMakF4TlNBeExqVTJNaTB1TkRNZ01TNDFOeTB1T1RsYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFRZdU5ERTBJREk0TGpnNVlURTFMamMzTnlBeE5TNDNOemNnTUNBd0lERXRNaTR3T1RNdE1pNHhORFpqTFM0NE5UWXRNUzR3TmpNdE1pNDBOVE10TXk0d09UTXRNaTQ1TnpVdE5pNHhNVEpoTVRFdU56WTFJREV4TGpjMk5TQXdJREFnTVMwdU1Ea3pMVE11TXpBM2JESTFMalF6TFRrdU9UYzJZeTR3TkRNdU1UUXlMakU0T0M0MU5UVXVOakEwTGpnMk9DNDBOaTR6TkRZdU9UUTNMak0wSURFdU1EZzJMak16TkV3MkxqUXhNeUF5T0M0NE9EaDJMakF3TWxvaUlHWnBiR3c5SWlORk5rVTJSVFlpTHo0OGNHRjBhQ0J2Y0dGamFYUjVQU0l1TXpNaUlHUTlJazB4TGpRM055QXhOaTR3TWpsakxqSTFMUzQ1TXpFdU56QTJMVEl1TWpVNElERXVOVGN0TXk0Mk9UVXVOalUxTFRFdU1Ea3lJREV1TWpreUxURXVPREkxSURFdU56WXRNaTR6TlRndU5UZzBMUzQyTmpVZ01TNDNOell0TVM0NU16UWdNeTQyTnprdE15NHlPU0F5TGprMU15MHlMakV3TlNBMUxqWTVOaTB6TGpBMUlEY3VOekl6TFRNdU56TmhNemN1TXpVZ016Y3VNelVnTUNBd0lERWdOaTQwT0RVdE1TNDFORGRzTlM0eU5ESWdOQzR6TVRaaE1TNDBPQ0F4TGpRNElEQWdNQ0F3TFRFdU1qRTBMamsyTjB3eExqUTRJREUyTGpBemFDMHVNREF5V2lJZ1ptbHNiRDBpSXprNU9TSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNDBOQ0lnWkQwaVRURXVPREVnTWpZdU5UTXlZeTR5TURZdU5EazBMalE0TkNBeExqQTFMamcySURFdU5qTmhNVEF1TWpZMklERXdMakkyTmlBd0lEQWdNQ0F5TGpJM09DQXlMalE0Tmt3MkxqVTFNaUEzT0M0eU1tRXhOeTR5TnpJZ01UY3VNamN5SURBZ01DQXhMVE10Tnk0ME1UTk1NUzQ0TVNBeU5pNDFNekphSWlCbWFXeHNQU0lqUlRaRk5rVTJJaTgrUEhCaGRHZ2daRDBpYlRNekxqQTVNaUEwT1M0ME5ERXROaTR6T0RFZ01UVXVNakV4Y3kwMkxqQTNPQzB4TVM0eE5Ua2dOaTR6T0RFdE1UVXVNakZhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEhCaGRHZ2daRDBpYlRJMkxqY3lOU0EyTkM0NE5UZ3RMakE1TVMwdU1UYzFZeTB1TURJMkxTNHdORGt0TWk0Mk16UXROQzQ1TWpNdExqZzJOeTA1TGpNM0lERXVNRFUzTFRJdU56RTNJRE11TlRFNExUUXVOekkxSURjdU15MDFMamswTm13dU1UZzNMUzR3TmpFdE5pNDFNeUF4TlM0MU5USmFiVFl1TWpFeUxURTFMakkyT0dNdE15NDJNakVnTVM0eU1UY3ROUzQ1T1RFZ015NHhOamd0Tnk0d01qSWdOUzQzT1RndE1TNDFNemdnTXk0NU1EZ3VNelUxSURndU1UWTJMamM0T0NBNUxqQTFOR3cyTGpJek5DMHhOQzQ0TlRKYVRUSTRMakE1TXlBMk15NDNNemRzTkM0ME9EUXRNVEF1T0Rkek55NHpOalVnTmk0ek16Y3ROQzQwT0RRZ01UQXVPRGRhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEM5blBqeG5JR2xrUFNKQ1JVRk9JajQ4Y21WamRDQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnM0lERXVNalkxTFRNdU5UQTBJRGt1TXpaVExqSTVPQ0F6TGprNU9TQTNMalk0TnlBeExqSTJObHB0TFRJdU5qa3hJRGd1TnpnZ01pNDBOakl0Tmk0Mk9URnpOQzQxTXpnZ015NDJOeTB5TGpRMk1pQTJMalk1TVZvaUlHWnBiR3c5SWlObVptWWlMejQ4TDJjK1BHY2dhV1E5SWtKRlFVNHpRMUpXSWo0OGNtVmpkQ0I1UFNJdU5TSWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE55QXhMamMyTkMwekxqVXdOQ0E1TGpNMlV5NHlPVGdnTkM0ME9Ua2dOeTQyT0RjZ01TNDNOalZhSWlCbWFXeHNQU0lqWm1abUlpOCtQSEJoZEdnZ1pEMGlUVGd1TVRNeUlEZ3VNRGM0WXkwdU5EWTJMalkwTFRFdU1qazNJREV1TXpJekxUSXVOamsxSURFdU9Ua3liREl1TVRJMkxUVXVOemMzWXk0d09Ea3VNRGt1TVRrekxqSXdOQzR6TGpNek9DNHpNRE11TXpjMUxqWXlOUzQ0T1RFdU56UTBJREV1TkRnMExqRXhOeTQxT0RNdU1EUWdNUzR5TlRNdExqUTNOU0F4TGprMk0xb2lJR1pwYkd3OUluVnliQ2dqWVNraUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMWGRwWkhSb1BTSXVOU0l2UGp4a1pXWnpQanhzYVc1bFlYSkhjbUZrYVdWdWRDQnBaRDBpWVNJZ2VERTlJall1T1RVaUlIa3hQU0l6TGpnMU15SWdlREk5SWpZdU9UVWlJSGt5UFNJeE1DNDFORFFpSUdkeVlXUnBaVzUwVlc1cGRITTlJblZ6WlhKVGNHRmpaVTl1VlhObElqNDhjM1J2Y0NCemRHOXdMV052Ykc5eVBTSWpPREl3TWpBeUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU1UZ3lJaUJ6ZEc5d0xXTnZiRzl5UFNJalJqY3hSVEExSWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TlRFMklpQnpkRzl3TFdOdmJHOXlQU0lqUmpCR05UQTNJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOek0wSWlCemRHOXdMV052Ykc5eVBTSWpPRFZEUkRjMUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeElpQnpkRzl3TFdOdmJHOXlQU0lqTURJNVJFWkNJaTgrUEM5c2FXNWxZWEpIY21Ga2FXVnVkRDQ4TDJSbFpuTStQQzluUGp4bklHbGtQU0oxY2tKRlFVNGlQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RjZ01TNHlOalV0TXk0MU1EUWdPUzR6TmxNdU1qazRJRE11T1RrNUlEY3VOamczSURFdU1qWTJXbTB0TWk0Mk9URWdPQzQzT0NBeUxqUTJNaTAyTGpZNU1YTTBMalV6T0NBekxqWTNMVEl1TkRZeUlEWXVOamt4V2lJZ1ptbHNiRDBpSTJabVppSXZQand2Wno0OFp5QnBaRDBpUWtWQlRrVlVTQ0krUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE5DQXhMakkyTlMwekxqVXdOU0E1TGpNMll5NHdNRE1nTUMwekxqZzROQzAyTGpZeU5TQXpMalV3TlMwNUxqTTJXaUlnWm1sc2JEMGlJMlptWmlJdlBqeHdZWFJvSUdROUlrMDRMamsxTWlBMkxqazRObUV1TURZekxqQTJNeUF3SURBZ01TMHVNREl5TGpBd00yTXRMamN4TGpFekxURXVOREkwTGpJMU5TMHlMakV6TkM0ek9ERXRMakk0TVM0d05USXRMalUyTlM0eE1ETXRMamcwTmk0eE5USmhMakF6Tmk0d016WWdNQ0F3SURFdExqQXlOaUF3YkRJdU1UUXROUzQyTWpVdU1EQTBMUzR3TUROakxqSTVOeUF4TGpjd01pNDFPU0F6TGpNNU5DNDRPRFFnTlM0d09USmFiUzB1TVRnM0xqUTNPR010TVM0eU5qWXVPRFU1TFRJdU5UTXhJREV1TnpJeExUTXVPQ0F5TGpVNGJDNDNPREV0TWk0d05UUmpMakF3Tnk0d01EUXVNREV6SURBZ0xqQXlNeUF3SUM0M05Ua3RMakV6TWlBeExqVXhOQzB1TWpZNElESXVNamN0TGpSc0xqWTVOeTB1TVRJMkxqQXpMUzR3TURaakxTNHdNRFF1TURBeklEQWdMakF3TmlBd0lDNHdNRFphSWlCbWFXeHNQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0oxY2tKRlFVNUZWRWdpUGp4eVpXTjBJSGRwWkhSb1BTSXhNaUlnYUdWcFoyaDBQU0l4TWlJZ2NuZzlJallpSUdacGJHdzlJaU0zUmpVMU16TWlMejQ4Y0dGMGFDQmtQU0p0Tnk0Mk9EUWdNUzR5TmpVdE15NDFNRFVnT1M0ek5tTXVNREF6SURBdE15NDRPRFF0Tmk0Mk1qVWdNeTQxTURVdE9TNHpObG9pSUdacGJHdzlJaU5tWm1ZaUx6NDhjR0YwYUNCa1BTSk5PQzQ1TlRJZ05pNDVPRFpoTGpBMk15NHdOak1nTUNBd0lERXRMakF5TWk0d01ETmpMUzQzTVM0eE15MHhMalF5TkM0eU5UVXRNaTR4TXpRdU16Z3hMUzR5T0RFdU1EVXlMUzQxTmpVdU1UQXpMUzQ0TkRZdU1UVXlZUzR3TXpZdU1ETTJJREFnTUNBeExTNHdNallnTUd3eUxqRTBMVFV1TmpJMUxqQXdOQzB1TURBell5NHlPVGNnTVM0M01ESXVOVGtnTXk0ek9UUXVPRGcwSURVdU1Ea3lXbTB0TGpFNE55NDBOemhqTFRFdU1qWTJMamcxT1MweUxqVXpNU0F4TGpjeU1TMHpMamdnTWk0MU9Hd3VOemd4TFRJdU1EVTBZeTR3TURjdU1EQTBMakF4TXlBd0lDNHdNak1nTUNBdU56VTVMUzR4TXpJZ01TNDFNVFF0TGpJMk9DQXlMakkzTFM0MGJDNDJPVGN0TGpFeU5pNHdNeTB1TURBMll5MHVNREEwTGpBd015QXdJQzR3TURZZ01DQXVNREEyV2lJZ1ptbHNiRDBpSXpBd01DSXZQand2Wno0OFp5QnBaRDBpYkdWaFpsSnZkeUkrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTUNJZ2VUMGlNQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweE1pSWdlVDBpTFRjaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXRNalFpSUhrOUlpMHhOQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkwek5pSWdlVDBpTFRJeElpOCtQQzluUGp3dlpHVm1jejQ4Y21WamRDQjNhV1IwYUQwaU1qVTFJaUJvWldsbmFIUTlJak0xTUNJZ2NuZzlJakV3SWlCbWFXeHNQU0lqTWpVek16STJJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYzJsc2J5SWdlRDBpT1RraUlIazlJalUxSWk4K1BHY2dhV1E5SW1Gc2JGQnNiM1FpSUdOc2FYQXRjR0YwYUQwaWRYSnNLQ05pYjNKa1pYSk5ZWE5yS1NJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTB4TmpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRFMk5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqQWlJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l0TVRJMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJdE9EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSTJPU0lnZVQwaUxUZzBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlMVEV6T0NJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTUNJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM05wYkc4aUlIZzlJalEzSWlCNVBTSTFOU0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpjcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU53WVhKMGFXRnNUR1ZoWmxCc2IzUWlJSGc5SWpFek9DSWdlVDBpTXpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlOamtpSUhrOUlqYzJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlMVEV6T0NJZ2VUMGlNVEUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU1DSWdlVDBpTVRFMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSTJPU0lnZVQwaU1UVTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlMVFk1SWlCNVBTSXhOVFlpSUM4K1BDOW5Qanh5WldOMElIZzlJakFpSUhrOUlqQWlJSGRwWkhSb1BTSXlOVFVpSUdobGFXZG9kRDBpTWpBaUlISjRQU0kxSWlCbWFXeHNQU0lqTWpReU5ESTBJaTgrUEhSbGVIUWdlRDBpTVRBaUlIazlJakUwTGpVaUlHWnZiblF0YzJsNlpUMGlNVElpSUdacGJHdzlJbGRvYVhSbElpQjBaWGgwTFdGdVkyaHZjajBpYzNSaGNuUWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUG5WeVFrVkJUa1ZVU0NCRVpYQnZjMmwwUEM5MFpYaDBQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM1Z5UWtWQlRrVlVTQ0lnZUQwaU1qUXdJaUI1UFNJMElpQXZQanh5WldOMElIZzlJakFpSUhrOUlqTXpNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1qY2lJSGs5SWpNME15SWdabTl1ZEMxemFYcGxQU0l4TUNJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKdGFXUmtiR1VpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBqeDBjM0JoYmo0OFlXNXBiV0YwWlNCaGRIUnlhV0oxZEdWT1lXMWxQU0o0SWlCbWNtOXRQU0l6TnpVaUlIUnZQU0kxTUNJZ1pIVnlQU0l4TUhNaUlISmxjR1ZoZEVOdmRXNTBQU0pwYm1SbFptbHVhWFJsSWlBdlBqQjRNV0psWVROalkyUXlNbVkwWldKa00yUXpOMlEzTXpGaVlUTXhaV1ZqWVRrMU56RXpOekUyWkR3dmRITndZVzQrUEM5MFpYaDBQangwWlhoMElIZzlJakV5TnlJZ2VUMGlNelF6SWlCbWIyNTBMWE5wZW1VOUlqRXdJaUJtYVd4c1BTSlhhR2wwWlNJZ2RHVjRkQzFoYm1Ob2IzSTlJbTFwWkdSc1pTSWdabTl1ZEMxbVlXMXBiSGs5SW1aMWRIVnlZU0krUEhSemNHRnVQanhoYm1sdFlYUmxJR0YwZEhKcFluVjBaVTVoYldVOUluZ2lJR1p5YjIwOUlqVXdJaUIwYnowaUxUSTNOU0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNE1XSmxZVE5qWTJReU1tWTBaV0prTTJRek4yUTNNekZpWVRNeFpXVmpZVGsxTnpFek56RTJaRHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqSXpOU0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSmxibVFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBsTjBaVzA2SUMweE5qWTRQQzkwWlhoMFBqd3ZjM1puUGc9PSJ9 \ No newline at end of file From d211b46cc314b968b93f87db1a4d1f80ca7ec88b Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 26 Sep 2023 13:49:53 -0400 Subject: [PATCH 45/96] add migrated BDV counter --- protocol/abi/Beanstalk.json | 19 +++++++++++++++++++ protocol/contracts/beanstalk/AppStorage.sol | 4 ++++ .../beanstalk/silo/MigrationFacet.sol | 8 ++++++++ .../libraries/Silo/LibLegacyTokenSilo.sol | 13 +++++++++++++ protocol/test/Stem.test.js | 12 +++++++++++- 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/protocol/abi/Beanstalk.json b/protocol/abi/Beanstalk.json index d9f419d093..611c91aea5 100644 --- a/protocol/abi/Beanstalk.json +++ b/protocol/abi/Beanstalk.json @@ -4420,6 +4420,25 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "totalMigratedBdv", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "anonymous": false, "inputs": [ diff --git a/protocol/contracts/beanstalk/AppStorage.sol b/protocol/contracts/beanstalk/AppStorage.sol index b3d3f33698..a6a54ffe7b 100644 --- a/protocol/contracts/beanstalk/AppStorage.sol +++ b/protocol/contracts/beanstalk/AppStorage.sol @@ -487,6 +487,7 @@ contract Storage { * @param ownerCandidate Stores a candidate address to transfer ownership to. The owner must claim the ownership transfer. * @param wellOracleSnapshots A mapping from Well Oracle address to the Well Oracle Snapshot. * @param beanEthPrice Stores the beanEthPrice during the sunrise() function. Returns 1 otherwise. + * @param migratedBdvs Stores the total migrated BDV since the implementation of the migrated BDV counter. See {LibLegacyTokenSilo.incrementMigratedBdv} for more info. */ struct AppStorage { uint8 deprecated_index; @@ -547,4 +548,7 @@ struct AppStorage { // Well mapping(address => bytes) wellOracleSnapshots; uint256 beanEthPrice; + + // Silo V3 BDV Migration + mapping(address => uint256) migratedBdvs; } \ No newline at end of file diff --git a/protocol/contracts/beanstalk/silo/MigrationFacet.sol b/protocol/contracts/beanstalk/silo/MigrationFacet.sol index 130d49e7c3..e5a34ad660 100644 --- a/protocol/contracts/beanstalk/silo/MigrationFacet.sol +++ b/protocol/contracts/beanstalk/silo/MigrationFacet.sol @@ -109,4 +109,12 @@ contract MigrationFacet is ReentrancyGuard { ); } + /** + * @dev Returns the total Migrated BDV since the implementation of the Migration BDV counter. + */ + function totalMigratedBdv(address token) external view returns (uint256) { + AppStorage storage s = LibAppStorage.diamondStorage(); + return s.migratedBdvs[token]; + } + } \ No newline at end of file diff --git a/protocol/contracts/libraries/Silo/LibLegacyTokenSilo.sol b/protocol/contracts/libraries/Silo/LibLegacyTokenSilo.sol index 4d1d38adf7..96262b4e49 100644 --- a/protocol/contracts/libraries/Silo/LibLegacyTokenSilo.sol +++ b/protocol/contracts/libraries/Silo/LibLegacyTokenSilo.sol @@ -350,6 +350,7 @@ library LibLegacyTokenSilo { // Include Deposit in the total Deposited BDV. LibTokenSilo.incrementTotalDepositedBdv(perTokenData.token, crateBDV); + incrementMigratedBdv(perTokenData.token, crateBDV); // add to running total of seeds migrateData.totalSeeds = migrateData.totalSeeds.add(crateBDV.mul(getSeedsPerToken(address(perTokenData.token))).toUint128()); @@ -558,4 +559,16 @@ library LibLegacyTokenSilo { delete s.a[account].withdrawals[token][season]; return amount; } + + /** + * @dev Increments the Migrated BDV counter for a given `token` by `bdv`. + * The `depositedBdv` variable in `Storage.AssetSilo` does not include unmigrated BDV and thus is not accurrate. + * In a potential future update, it will be necessary for `depositedBdv` to include unmigrated BDV. + * By summating the `migratedBdv` counter, we can properly account for unmigrated BDV through + * a 2 step asynchronous upgrade process where adding this counter is the first step. + */ + function incrementMigratedBdv(address token, uint256 bdv) private { + AppStorage storage s = LibAppStorage.diamondStorage(); + s.migratedBdvs[token] = s.migratedBdvs[token].add(bdv); + } } diff --git a/protocol/test/Stem.test.js b/protocol/test/Stem.test.js index 53789aead7..2bbbdcd830 100644 --- a/protocol/test/Stem.test.js +++ b/protocol/test/Stem.test.js @@ -16,6 +16,7 @@ const { setEthUsdPrice, setEthUsdcPrice } = require('../utils/oracle.js'); const { impersonateEthUsdChainlinkAggregator, impersonateEthUsdcUniswap, impersonateBean, impersonateWeth } = require('../scripts/impersonate.js'); const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); const { finishBeanEthMigration } = require('../scripts/beanEthMigration.js'); +const { toBN } = require('../utils/helpers.js'); require('dotenv').config(); let user,user2,owner; @@ -159,15 +160,20 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { const seasons = [[6074],[6061],[6137]]; const amounts = []; - for(let i=0; i Date: Thu, 28 Sep 2023 08:27:26 -0400 Subject: [PATCH 46/96] add UsdOracle contract --- .../contracts/ecosystem/oracles/UsdOracle.sol | 23 +++++++++++++++++++ protocol/scripts/bips.js | 12 ++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 protocol/contracts/ecosystem/oracles/UsdOracle.sol diff --git a/protocol/contracts/ecosystem/oracles/UsdOracle.sol b/protocol/contracts/ecosystem/oracles/UsdOracle.sol new file mode 100644 index 0000000000..49c9ee1d6d --- /dev/null +++ b/protocol/contracts/ecosystem/oracles/UsdOracle.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity =0.7.6; +pragma experimental ABIEncoderV2; + +import {LibUsdOracle, LibEthUsdOracle} from "contracts/libraries/Oracle/LibUsdOracle.sol"; + +/** + * @title UsdOracle + * @author Publius + * @notice Holds functions to query USD prices of tokens. + */ +contract UsdOracle { + + function getUsdPrice(address token) external view returns (uint256) { + return LibUsdOracle.getUsdPrice(token); + } + + function getEthUsdPrice() external view returns (uint256) { + return LibEthUsdOracle.getEthUsdPrice(); + } + +} diff --git a/protocol/scripts/bips.js b/protocol/scripts/bips.js index b9a2bb19cd..feb9ddaf29 100644 --- a/protocol/scripts/bips.js +++ b/protocol/scripts/bips.js @@ -1,5 +1,6 @@ const { BEANSTALK } = require("../test/utils/constants"); -const { getBeanstalk, impersonateBeanstalkOwner, mintEth } = require("../utils"); +const { getBeanstalk, impersonateBeanstalkOwner, mintEth, impersonateSigner } = require("../utils"); +const { deployContract } = require("./contracts"); const { upgradeWithNewFacets } = require("./diamond"); const { impersonatePipeline, deployPipeline } = require("./pipeline"); @@ -144,7 +145,7 @@ async function bip34(mock = true, account = undefined) { verify: false }); } -async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefined, verbose = true) { +async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefined, verbose = true, oracleAccount = undefined) { if (account == undefined) { account = await impersonateBeanstalkOwner(); await mintEth(account.address); @@ -171,6 +172,13 @@ async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefine verify: false }); + + if (oracleAccount == undefined) { + oracleAccount = await impersonateSigner('0x30a1976d5d087ef0BA0B4CDe87cc224B74a9c752', true); // Oracle deployer + await mintEth(oracleAccount.address); + } + await deployContract('UsdOracle', oracleAccount, true) + } exports.bip29 = bip29 From f7d0d13c1d620d937e8380501f4ca9c8aab41aa6 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 11 Oct 2023 19:17:59 +0100 Subject: [PATCH 47/96] revert projects/ui/src/graph/graphql.schema.json --- projects/ui/src/graph/graphql.schema.json | 3038 +-------------------- 1 file changed, 4 insertions(+), 3034 deletions(-) diff --git a/projects/ui/src/graph/graphql.schema.json b/projects/ui/src/graph/graphql.schema.json index 5a41d47910..0cbf867354 100644 --- a/projects/ui/src/graph/graphql.schema.json +++ b/projects/ui/src/graph/graphql.schema.json @@ -16572,22 +16572,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "overall", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "pool", "description": null, @@ -17452,70 +17436,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "overall", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "overall_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "overall_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "overall_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "pool", "description": null, @@ -18897,12 +18817,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "overall", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "pool", "description": null, @@ -105220,176 +105134,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "wellOracle", - "description": null, - "args": [ - { - "name": "block", - "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", - "type": { - "kind": "INPUT_OBJECT", - "name": "Block_height", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subgraphError", - "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_SubgraphErrorPolicy_", - "ofType": null - } - }, - "defaultValue": "deny", - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "wellOracles", - "description": null, - "args": [ - { - "name": "block", - "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", - "type": { - "kind": "INPUT_OBJECT", - "name": "Block_height", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": "100", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "WellOracle_orderBy", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orderDirection", - "description": null, - "type": { - "kind": "ENUM", - "name": "OrderDirection", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": "0", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subgraphError", - "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_SubgraphErrorPolicy_", - "ofType": null - } - }, - "defaultValue": "deny", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "where", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "whitelistToken", "description": null, @@ -125507,11 +125251,6 @@ "name": "StalkChange", "ofType": null }, - { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - }, { "kind": "OBJECT", "name": "WhitelistToken", @@ -131078,41 +130817,9 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "fourPointFiveSeedBeanAPY", - "description": "Bean APY for 4.5 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY", - "description": "Stalk APY for 4.5 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "fourSeedBeanAPY", - "description": "Bean APY for 4 seeds per BDV", + "description": "Bean APY for four seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -131128,7 +130835,7 @@ }, { "name": "fourSeedStalkAPY", - "description": "Stalk APY for 4 seeds per BDV", + "description": "Stalk APY for four seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -131174,73 +130881,9 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "threePointTwoFiveSeedBeanAPY", - "description": "Bean APY for 3.25 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY", - "description": "Stalk APY for 3.25 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY", - "description": "Bean APY for 3 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY", - "description": "Stalk APY for 3 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "twoSeedBeanAPY", - "description": "Bean APY for 2 seeds per BDV", + "description": "Bean APY for two seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -131256,7 +130899,7 @@ }, { "name": "twoSeedStalkAPY", - "description": "Stalk APY for 2 seeds per BDV", + "description": "Stalk APY for two seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -131285,22 +130928,6 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY", - "description": "Bean APY for 0 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, @@ -131678,230 +131305,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "fourPointFiveSeedBeanAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "fourSeedBeanAPY", "description": null, @@ -132366,454 +131769,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "threePointTwoFiveSeedBeanAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "twoSeedBeanAPY", "description": null, @@ -133149,118 +132104,6 @@ "defaultValue": null, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null } ], "interfaces": null, @@ -133293,18 +132136,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "fourPointFiveSeedBeanAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "fourSeedBeanAPY", "description": null, @@ -133329,30 +132160,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "threePointTwoFiveSeedBeanAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "twoSeedBeanAPY", "description": null, @@ -133370,12 +132177,6 @@ "description": null, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null } ], "possibleTypes": null @@ -148307,176 +147108,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "wellOracle", - "description": null, - "args": [ - { - "name": "block", - "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", - "type": { - "kind": "INPUT_OBJECT", - "name": "Block_height", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subgraphError", - "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_SubgraphErrorPolicy_", - "ofType": null - } - }, - "defaultValue": "deny", - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "wellOracles", - "description": null, - "args": [ - { - "name": "block", - "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", - "type": { - "kind": "INPUT_OBJECT", - "name": "Block_height", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": "100", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "WellOracle_orderBy", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orderDirection", - "description": null, - "type": { - "kind": "ENUM", - "name": "OrderDirection", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": "0", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subgraphError", - "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_SubgraphErrorPolicy_", - "ofType": null - } - }, - "defaultValue": "deny", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "where", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "whitelistToken", "description": null, @@ -150336,1667 +148967,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "OBJECT", - "name": "WellOracle", - "description": null, - "fields": [ - { - "name": "blockNumber", - "description": " Block number of this event ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": " Timestamp of this event ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves", - "description": " Time weighted cumulative reserves ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB", - "description": " DeltaB for season", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash", - "description": " Transaction hash of the transaction that emitted this event ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "wellOracle-{ Transaction hash }-{ Log index }", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex", - "description": " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol", - "description": " The protocol this transaction belongs to ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Beanstalk", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season", - "description": " Season of oracle ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "SiloEvent", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "description": null, - "fields": null, - "inputFields": [ - { - "name": "_change_block", - "description": "Filter for the block changed event.", - "type": { - "kind": "INPUT_OBJECT", - "name": "BlockChangedFilter", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "and", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_not_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_contains_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_ends_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_ends_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_contains_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_ends_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_ends_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_starts_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_starts_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_starts_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_starts_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "or", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "Beanstalk_filter", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_contains_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_ends_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_ends_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_contains_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_ends_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_ends_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_starts_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_starts_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_starts_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_starts_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "WellOracle_orderBy", - "description": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "blockNumber", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__id", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__lastSeason", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__lastUpgrade", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__methodologyVersion", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__name", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__schemaVersion", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__slug", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__subgraphVersion", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, { "kind": "OBJECT", "name": "WhitelistToken", From 7281684d8085dcc8f2cdab41856cef8be116a533 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:48:40 -0400 Subject: [PATCH 48/96] update IWell.sol --- protocol/contracts/interfaces/basin/IWell.sol | 162 +++++++++++------- 1 file changed, 96 insertions(+), 66 deletions(-) diff --git a/protocol/contracts/interfaces/basin/IWell.sol b/protocol/contracts/interfaces/basin/IWell.sol index 84f0f8e5a0..bdb3dfe83c 100644 --- a/protocol/contracts/interfaces/basin/IWell.sol +++ b/protocol/contracts/interfaces/basin/IWell.sol @@ -15,6 +15,10 @@ struct Call { /** * @title IWell is the interface for the Well contract. + * + * In order for a Well to be verified using a permissionless on-chain registry, a Well Implementation should: + * - Not be able to self-destruct (Aquifer's registry would be vulnerable to a metamorphic contract attack) + * - Not be able to change its tokens, Well Function, Pumps and Well Data */ interface IWell { /** @@ -23,53 +27,55 @@ interface IWell { * @param toToken The token swapped to * @param amountIn The amount of `fromToken` transferred into the Well * @param amountOut The amount of `toToken` transferred out of the Well - * @param recipient The address to receive `toToken` + * @param recipient The address that received `toToken` */ - event Swap(IERC20 fromToken, IERC20 toToken, uint amountIn, uint amountOut, address recipient); + event Swap(IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 amountOut, address recipient); /** * @notice Emitted when liquidity is added to the Well. * @param tokenAmountsIn The amount of each token added to the Well * @param lpAmountOut The amount of LP tokens minted - * @param recipient The address to receive the LP tokens + * @param recipient The address that received the LP tokens */ - event AddLiquidity(uint[] tokenAmountsIn, uint lpAmountOut, address recipient); + event AddLiquidity(uint256[] tokenAmountsIn, uint256 lpAmountOut, address recipient); /** * @notice Emitted when liquidity is removed from the Well as multiple underlying tokens. * @param lpAmountIn The amount of LP tokens burned * @param tokenAmountsOut The amount of each underlying token removed - * @param recipient The address to receive the underlying tokens + * @param recipient The address that received the underlying tokens * @dev Gas cost scales with `n` tokens. */ - event RemoveLiquidity(uint lpAmountIn, uint[] tokenAmountsOut, address recipient); + event RemoveLiquidity(uint256 lpAmountIn, uint256[] tokenAmountsOut, address recipient); /** * @notice Emitted when liquidity is removed from the Well as a single underlying token. * @param lpAmountIn The amount of LP tokens burned * @param tokenOut The underlying token removed * @param tokenAmountOut The amount of `tokenOut` removed - * @param recipient The address to receive the underlying tokens + * @param recipient The address that received the underlying tokens * @dev Emitting a separate event when removing liquidity as a single token * saves gas, since `tokenAmountsOut` in {RemoveLiquidity} must emit a value * for each token in the Well. */ - event RemoveLiquidityOneToken(uint lpAmountIn, IERC20 tokenOut, uint tokenAmountOut, address recipient); + event RemoveLiquidityOneToken(uint256 lpAmountIn, IERC20 tokenOut, uint256 tokenAmountOut, address recipient); /** * @notice Emitted when a Shift occurs. * @param reserves The ending reserves after a shift * @param toToken The token swapped to - * @param minAmountOut The minimum amount of `toToken` transferred out of the Well - * @param recipient The address to receive `toToken` + * @param amountOut The amount of `toToken` transferred out of the Well + * @param recipient The address that received `toToken` */ - event Shift(uint[] reserves, IERC20 toToken, uint minAmountOut, address recipient); + event Shift(uint256[] reserves, IERC20 toToken, uint256 amountOut, address recipient); /** * @notice Emitted when a Sync occurs. * @param reserves The ending reserves after a sync + * @param lpAmountOut The amount of LP tokens received from the sync. + * @param recipient The address that received the LP tokens */ - event Sync(uint[] reserves); + event Sync(uint256[] reserves, uint256 lpAmountOut, address recipient); //////////////////// WELL DEFINITION //////////////////// @@ -149,11 +155,11 @@ interface IWell { function swapFrom( IERC20 fromToken, IERC20 toToken, - uint amountIn, - uint minAmountOut, + uint256 amountIn, + uint256 minAmountOut, address recipient, - uint deadline - ) external returns (uint amountOut); + uint256 deadline + ) external returns (uint256 amountOut); /** * @notice Swaps from an exact amount of `fromToken` to a minimum amount of `toToken` and supports fee on transfer tokens. @@ -169,11 +175,11 @@ interface IWell { function swapFromFeeOnTransfer( IERC20 fromToken, IERC20 toToken, - uint amountIn, - uint minAmountOut, + uint256 amountIn, + uint256 minAmountOut, address recipient, - uint deadline - ) external returns (uint amountOut); + uint256 deadline + ) external returns (uint256 amountOut); /** * @notice Gets the amount of one token received for swapping an amount of another token. @@ -182,7 +188,7 @@ interface IWell { * @param amountIn The amount of `fromToken` to spend * @return amountOut The amount of `toToken` to receive */ - function getSwapOut(IERC20 fromToken, IERC20 toToken, uint amountIn) external view returns (uint amountOut); + function getSwapOut(IERC20 fromToken, IERC20 toToken, uint256 amountIn) external view returns (uint256 amountOut); //////////////////// SWAP: TO //////////////////// @@ -199,11 +205,11 @@ interface IWell { function swapTo( IERC20 fromToken, IERC20 toToken, - uint maxAmountIn, - uint amountOut, + uint256 maxAmountIn, + uint256 amountOut, address recipient, - uint deadline - ) external returns (uint amountIn); + uint256 deadline + ) external returns (uint256 amountIn); /** * @notice Gets the amount of one token that must be spent to receive an amount of another token during a swap. @@ -212,28 +218,28 @@ interface IWell { * @param amountOut The amount of `toToken` desired * @return amountIn The amount of `fromToken` that must be spent */ - function getSwapIn(IERC20 fromToken, IERC20 toToken, uint amountOut) external view returns (uint amountIn); + function getSwapIn(IERC20 fromToken, IERC20 toToken, uint256 amountOut) external view returns (uint256 amountIn); //////////////////// SHIFT //////////////////// /** - * @notice Shifts excess tokens held by the Well into `tokenOut` and delivers to `recipient`. + * @notice Shifts at least `minAmountOut` excess tokens held by the Well into `tokenOut` and delivers to `recipient`. * @param tokenOut The token to shift into * @param minAmountOut The minimum amount of `tokenOut` to receive * @param recipient The address to receive the token * @return amountOut The amount of `tokenOut` received - * @dev Gas optimization: we leave the responsibility of checking a transaction - * deadline to a wrapper contract like {Pipeline} to prevent repeated deadline - * checks on each hop of a multi-step transaction. + * @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient swaps. + * No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall, + * then a deadline check can be added to the multicall. */ - function shift(IERC20 tokenOut, uint minAmountOut, address recipient) external returns (uint amountOut); + function shift(IERC20 tokenOut, uint256 minAmountOut, address recipient) external returns (uint256 amountOut); /** * @notice Calculates the amount of the token out received from shifting excess tokens held by the Well. * @param tokenOut The token to shift into * @return amountOut The amount of `tokenOut` received */ - function getShiftOut(IERC20 tokenOut) external returns (uint amountOut); + function getShiftOut(IERC20 tokenOut) external returns (uint256 amountOut); //////////////////// ADD LIQUIDITY //////////////////// @@ -246,11 +252,11 @@ interface IWell { * @return lpAmountOut The amount of LP tokens received */ function addLiquidity( - uint[] memory tokenAmountsIn, - uint minLpAmountOut, + uint256[] memory tokenAmountsIn, + uint256 minLpAmountOut, address recipient, - uint deadline - ) external returns (uint lpAmountOut); + uint256 deadline + ) external returns (uint256 lpAmountOut); /** * @notice Adds liquidity to the Well as multiple tokens in any ratio and supports @@ -263,18 +269,18 @@ interface IWell { * @dev Can also be used for tokens without a fee on transfer, but is less gas efficient. */ function addLiquidityFeeOnTransfer( - uint[] memory tokenAmountsIn, - uint minLpAmountOut, + uint256[] memory tokenAmountsIn, + uint256 minLpAmountOut, address recipient, - uint deadline - ) external returns (uint lpAmountOut); + uint256 deadline + ) external returns (uint256 lpAmountOut); /** * @notice Gets the amount of LP tokens received from adding liquidity as multiple tokens in any ratio. * @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens} - * @return lpAmountOut The amount of LP tokens to receive + * @return lpAmountOut The amount of LP tokens received */ - function getAddLiquidityOut(uint[] memory tokenAmountsIn) external view returns (uint lpAmountOut); + function getAddLiquidityOut(uint256[] memory tokenAmountsIn) external view returns (uint256 lpAmountOut); //////////////////// REMOVE LIQUIDITY: BALANCED //////////////////// @@ -287,18 +293,18 @@ interface IWell { * @return tokenAmountsOut The amount of each underlying token received */ function removeLiquidity( - uint lpAmountIn, - uint[] calldata minTokenAmountsOut, + uint256 lpAmountIn, + uint256[] calldata minTokenAmountsOut, address recipient, - uint deadline - ) external returns (uint[] memory tokenAmountsOut); + uint256 deadline + ) external returns (uint256[] memory tokenAmountsOut); /** * @notice Gets the amount of each underlying token received from removing liquidity in a balanced ratio. * @param lpAmountIn The amount of LP tokens to burn - * @return tokenAmountsOut The amount of each underlying token to receive + * @return tokenAmountsOut The amount of each underlying token received */ - function getRemoveLiquidityOut(uint lpAmountIn) external view returns (uint[] memory tokenAmountsOut); + function getRemoveLiquidityOut(uint256 lpAmountIn) external view returns (uint256[] memory tokenAmountsOut); //////////////////// REMOVE LIQUIDITY: ONE TOKEN //////////////////// @@ -312,24 +318,24 @@ interface IWell { * @return tokenAmountOut The amount of `tokenOut` received */ function removeLiquidityOneToken( - uint lpAmountIn, + uint256 lpAmountIn, IERC20 tokenOut, - uint minTokenAmountOut, + uint256 minTokenAmountOut, address recipient, - uint deadline - ) external returns (uint tokenAmountOut); + uint256 deadline + ) external returns (uint256 tokenAmountOut); /** * @notice Gets the amount received from removing liquidity from the Well as a single underlying token. * @param lpAmountIn The amount of LP tokens to burn * @param tokenOut The underlying token to receive - * @return tokenAmountOut The amount of `tokenOut` to receive + * @return tokenAmountOut The amount of `tokenOut` received * */ function getRemoveLiquidityOneTokenOut( - uint lpAmountIn, + uint256 lpAmountIn, IERC20 tokenOut - ) external view returns (uint tokenAmountOut); + ) external view returns (uint256 tokenAmountOut); //////////////////// REMOVE LIQUIDITY: IMBALANCED //////////////////// @@ -341,35 +347,59 @@ interface IWell { * @return lpAmountIn The amount of LP tokens burned */ function removeLiquidityImbalanced( - uint maxLpAmountIn, - uint[] calldata tokenAmountsOut, + uint256 maxLpAmountIn, + uint256[] calldata tokenAmountsOut, address recipient, - uint deadline - ) external returns (uint lpAmountIn); + uint256 deadline + ) external returns (uint256 lpAmountIn); /** * @notice Gets the amount of LP tokens to burn from removing liquidity as multiple underlying tokens in any ratio. * @param tokenAmountsOut The amount of each underlying token to receive; MUST match the indexing of {Well.tokens} - * @return lpAmountIn The amount of LP tokens to burn + * @return lpAmountIn The amount of LP tokens burned */ - function getRemoveLiquidityImbalancedIn(uint[] calldata tokenAmountsOut) external view returns (uint lpAmountIn); + function getRemoveLiquidityImbalancedIn(uint256[] calldata tokenAmountsOut) + external + view + returns (uint256 lpAmountIn); //////////////////// RESERVES //////////////////// /** - * @notice Syncs the reserves of the Well with the Well's balances of underlying tokens. + * @notice Syncs the Well's reserves with the Well's balances of underlying tokens. If the reserves + * increase, mints at least `minLpAmountOut` LP Tokens to `recipient`. + * @param recipient The address to receive the LP tokens + * @param minLpAmountOut The minimum amount of LP tokens to receive + * @return lpAmountOut The amount of LP tokens received + * @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient additions of liquidity. + * No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall, + * then a deadline check can be added to the multicall. + * If `sync` decreases the Well's reserves, then no LP tokens are minted and `lpAmountOut` must be 0. */ - function sync() external; + function sync(address recipient, uint256 minLpAmountOut) external returns (uint256 lpAmountOut); + + /** + * @notice Calculates the amount of LP Tokens received from syncing the Well's reserves with the Well's balances. + * @return lpAmountOut The amount of LP tokens received + */ + function getSyncOut() external view returns (uint256 lpAmountOut); /** * @notice Sends excess tokens held by the Well to the `recipient`. * @param recipient The address to send the tokens * @return skimAmounts The amount of each token skimmed + * @dev No deadline is needed since this function does not use the user's assets. */ - function skim(address recipient) external returns (uint[] memory skimAmounts); + function skim(address recipient) external returns (uint256[] memory skimAmounts); /** * @notice Gets the reserves of each token held by the Well. */ - function getReserves() external view returns (uint[] memory reserves); -} + function getReserves() external view returns (uint256[] memory reserves); + + /** + * @notice Returns whether or not the Well is initialized if it requires initialization. + * If a Well does not require initialization, it should always return `true`. + */ + function isInitialized() external view returns (bool); +} \ No newline at end of file From 7aa54c0e08526f497dfad4e405e430cddef331a8 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:50:04 -0400 Subject: [PATCH 49/96] Mint Fertilizer with WETH and add liquidity to Bean:Eth Well instead of USDC + Bean:3Crv Curve pool --- .../beanstalk/barn/FertilizerFacet.sol | 77 ++++++-- .../contracts/libraries/LibFertilizer.sol | 65 ++++--- protocol/test/Fertilizer.test.js | 170 ++++++++++-------- 3 files changed, 201 insertions(+), 111 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index a6b8b36de0..fdcc4179f6 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -5,10 +5,16 @@ pragma solidity ^0.7.6; pragma experimental ABIEncoderV2; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol"; +import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; +import {IFertilizer} from "contracts/interfaces/IFertilizer.sol"; import {AppStorage} from "../AppStorage.sol"; -import "contracts/libraries/Token/LibTransfer.sol"; -import "contracts/libraries/LibFertilizer.sol"; -import "contracts/C.sol"; +import {LibTransfer} from "contracts/libraries/Token/LibTransfer.sol"; +import {LibEthUsdOracle} from "contracts/libraries/Oracle/LibEthUsdOracle.sol"; +import {LibFertilizer} from "contracts/libraries/LibFertilizer.sol"; +import {LibSafeMath128} from "contracts/libraries/LibSafeMath128.sol"; +import {C} from "contracts/C.sol"; import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; /** @@ -18,6 +24,7 @@ import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; contract FertilizerFacet { using SafeMath for uint256; + using SafeCast for uint256; using LibSafeMath128 for uint128; event SetFertilizer(uint128 id, uint128 bpf); @@ -37,39 +44,79 @@ contract FertilizerFacet { LibTransfer.sendToken(C.bean(), amount, msg.sender, mode); } + /** + * @dev Returns the amount of Fertilize that can be purchased with `wethAmountIn` WETH. + * Can be used to help calculate `minFertilizerOut` in `mintFertilizer` + */ + function getMintFertilizerOut( + uint128 wethAmountIn + ) external view returns (uint256 fertilizerAmountOut) { + fertilizerAmountOut = amount.mul( + LibEthUsdOracle.getEthUsdPrice() + ).div(1e24); + } + + /** + * @notice Purchase Fertilizer from the Barn Raise with WETH. + * @param wethAmountIn Amount of WETH to buy Fertilizer with 18 decimal precision. + * @param minFertilizerOut The minimum amount of Fertilizer to purchase. + * @param minLP The minimum amount of LP to receive after. + * @param mode The balance to transfer Beans to; see {LibTrasfer.To} + * @dev The # of Fertilizer minted is equal to the value of the Ether paid in USD. + */ function mintFertilizer( - uint128 amount, + uint256 wethAmountIn, + uint256 minFertilizerOut, uint256 minLP, LibTransfer.From mode - ) external payable { - uint128 remaining = uint128(LibFertilizer.remainingRecapitalization().div(1e6)); // remaining <= 77_000_000 so downcasting is safe. - if (amount > remaining) amount = remaining; - amount = uint128(LibTransfer.receiveToken( - C.usdc(), - uint256(amount).mul(1e6), + ) external payable returns (uint256 fertilizerAmountOut) { + + amount = LibTransfer.receiveToken( + IERC20(C.WETH), + uint256(amount), msg.sender, mode - ).div(1e6)); // return value <= amount, so downcasting is safe. + ); // return value <= amount, so downcasting is safe. + + // Convert from Ether amount with 18 decimals to USD amount with 0 decimals. + fertilizerAmountOut = amount.mul( + LibEthUsdOracle.getEthUsdPrice() + ).div(1e24); + + require(fertilizerAmountOut >= minFertilizerOut, "Fertilizer Not enough bought."); + + uint128 remaining = uint128(LibFertilizer.remainingRecapitalization().div(1e6)); // remaining <= 77_000_000 so downcasting is safe. + require(fertilizerAmountOut <= remaining, "Fertilizer: Not enough remaining."); + uint128 id = LibFertilizer.addFertilizer( uint128(s.season.current), amount, + fertilizerAmountOut, minLP ); - C.fertilizer().beanstalkMint(msg.sender, uint256(id), amount, s.bpf); + C.fertilizer().beanstalkMint(msg.sender, uint256(id), (fertilizerAmountOut).toUint128(), s.bpf); } + /** + * @notice Contributes to Barn Raise on behalf of existing fertilizer holders. + */ function addFertilizerOwner( uint128 id, uint128 amount, uint256 minLP ) external payable { LibDiamond.enforceIsContractOwner(); - C.usdc().transferFrom( + IERC20(C.WETH).transferFrom( msg.sender, address(this), - uint256(amount).mul(1e6) + uint256(amount) ); - LibFertilizer.addFertilizer(id, amount, minLP); + + uint256 fertilizerAmount = uint256(amount).mul( + LibEthUsdOracle.getEthUsdPrice() + ).div(1e24); + + LibFertilizer.addFertilizer(id, amount, fertilizerAmount, minLP); } function payFertilizer(address account, uint256 amount) external payable { diff --git a/protocol/contracts/libraries/LibFertilizer.sol b/protocol/contracts/libraries/LibFertilizer.sol index 583b0c63af..f59cbfb6ea 100644 --- a/protocol/contracts/libraries/LibFertilizer.sol +++ b/protocol/contracts/libraries/LibFertilizer.sol @@ -5,11 +5,14 @@ pragma solidity =0.7.6; pragma experimental ABIEncoderV2; -import "@openzeppelin/contracts/math/SafeMath.sol"; -import "./LibAppStorage.sol"; -import "./LibSafeMath128.sol"; -import "../C.sol"; -import "./LibUnripe.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol"; +import {AppStorage, LibAppStorage} from "./LibAppStorage.sol"; +import {LibSafeMath128} from "./LibSafeMath128.sol"; +import {C} from "../C.sol"; +import {LibUnripe} from "./LibUnripe.sol"; +import {IWell} from "contracts/interfaces/basin/IWell.sol"; /** * @author Publius @@ -19,6 +22,7 @@ import "./LibUnripe.sol"; library LibFertilizer { using SafeMath for uint256; using LibSafeMath128 for uint128; + using SafeCast for uint256; event SetFertilizer(uint128 id, uint128 bpf); @@ -31,27 +35,30 @@ library LibFertilizer { function addFertilizer( uint128 season, - uint128 amount, + uint256 amount, + uint256 fertilizerAmount, uint256 minLP ) internal returns (uint128 id) { AppStorage storage s = LibAppStorage.diamondStorage(); - uint256 _amount = uint256(amount); + + uint128 fertilizerAmount128 = fertilizerAmount.toUint128(); + // Calculate Beans Per Fertilizer and add to total owed uint128 bpf = getBpf(season); s.unfertilizedIndex = s.unfertilizedIndex.add( - _amount.mul(uint128(bpf)) + fertilizerAmount.mul(bpf) ); // Get id id = s.bpf.add(bpf); // Update Total and Season supply - s.fertilizer[id] = s.fertilizer[id].add(amount); - s.activeFertilizer = s.activeFertilizer.add(_amount); + s.fertilizer[id] = s.fertilizer[id].add(fertilizerAmount128); + s.activeFertilizer = s.activeFertilizer.add(fertilizerAmount); // Add underlying to Unripe Beans and Unripe LP - addUnderlying(_amount.mul(DECIMALS), minLP); + addUnderlying(amount, fertilizerAmount.mul(DECIMALS), minLP); // If not first time adding Fertilizer with this id, return - if (s.fertilizer[id] > amount) return id; + if (s.fertilizer[id] > fertilizerAmount128) return id; // If first time, log end Beans Per Fertilizer and add to Season queue. - LibFertilizer.push(id); + push(id); emit SetFertilizer(id, bpf); } @@ -66,10 +73,10 @@ library LibFertilizer { humidity = RESTART_HUMIDITY.sub(humidityDecrease); } - function addUnderlying(uint256 amount, uint256 minAmountOut) internal { + function addUnderlying(uint256 amount, uint256 usdAmount, uint256 minAmountOut) internal { AppStorage storage s = LibAppStorage.diamondStorage(); // Calculate how many new Deposited Beans will be minted - uint256 percentToFill = amount.mul(C.precision()).div( + uint256 percentToFill = usdAmount.mul(C.precision()).div( remainingRecapitalization() ); uint256 newDepositedBeans; @@ -83,25 +90,37 @@ library LibFertilizer { } // Calculate how many Beans to add as LP - uint256 newDepositedLPBeans = amount.mul(C.exploitAddLPRatio()).div( + uint256 newDepositedLPBeans = usdAmount.mul(C.exploitAddLPRatio()).div( DECIMALS ); - // Mint the Beans + + // Mint the Deposited Beans to Beanstalk. C.bean().mint( address(this), - newDepositedBeans.add(newDepositedLPBeans) + newDepositedBeans + ); + + // Mint the LP Beans to the Well to sync. + C.bean().mint( + address(C.BEAN_ETH_WELL), + newDepositedLPBeans ); - // Add Liquidity - uint256 newLP = C.curveZap().add_liquidity( - C.CURVE_BEAN_METAPOOL, - [newDepositedLPBeans, 0, amount, 0], + + IERC20(C.WETH).transfer( + address(C.BEAN_ETH_WELL), + amount + ); + + uint256 newLP = IWell(C.BEAN_ETH_WELL).sync( + address(this), minAmountOut ); + // Increment underlying balances of Unripe Tokens LibUnripe.incrementUnderlying(C.UNRIPE_BEAN, newDepositedBeans); LibUnripe.incrementUnderlying(C.UNRIPE_LP, newLP); - s.recapitalized = s.recapitalized.add(amount); + s.recapitalized = s.recapitalized.add(usdAmount); } function push(uint128 id) internal { diff --git a/protocol/test/Fertilizer.test.js b/protocol/test/Fertilizer.test.js index f0a608fa84..4519aef102 100644 --- a/protocol/test/Fertilizer.test.js +++ b/protocol/test/Fertilizer.test.js @@ -1,10 +1,12 @@ const { expect } = require('chai'); const { deploy } = require('../scripts/deploy.js') -const { deployFertilizer, impersonateFertilizer } = require('../scripts/deployFertilizer.js') +const { impersonateFertilizer } = require('../scripts/deployFertilizer.js') const { EXTERNAL, INTERNAL } = require('./utils/balances.js') -const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); -const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP } = require('./utils/constants'); +const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot.js"); +const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK } = require('./utils/constants.js'); +const { setEthUsdcPrice, setEthUsdPrice } = require('../utils/oracle.js'); const { to6, to18 } = require('./utils/helpers.js'); +const { deployBasin } = require('../scripts/basin.js'); let user,user2,owner,fert let userAddress, ownerAddress, user2Address @@ -41,23 +43,36 @@ describe('Fertilize', function () { this.token = await ethers.getContractAt('TokenFacet', this.diamond.address) this.usdc = await ethers.getContractAt('IBean', USDC) this.bean = await ethers.getContractAt('IBean', BEAN) - this.beanMetapool = await ethers.getContractAt('IBean', BEAN_3_CURVE) - this.threeCurve = await ethers.getContractAt('IBean', THREE_CURVE) + this.well = await ethers.getContractAt('IBean', BEAN_3_CURVE) + this.weth = await ethers.getContractAt('IBean', THREE_CURVE) + this.weth = await ethers.getContractAt('IBean', WETH) this.unripeBean = await ethers.getContractAt('MockToken', UNRIPE_BEAN) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) await this.unripeBean.mint(user2.address, to6('1000')) await this.unripeLP.mint(user2.address, to6('942.297473')) - this.threeCurve = await ethers.getContractAt('IBean', THREE_CURVE) - this.threeCurve = await ethers.getContractAt('IBean', THREE_CURVE) + this.weth = await ethers.getContractAt('IBean', WETH) + + await this.bean.mint(owner.address, to18('1000000000')); + await this.weth.mint(owner.address, to18('1000000000')); + await this.weth.mint(user.address, to18('1000000000')); + await this.weth.mint(user2.address, to18('1000000000')); + await this.bean.connect(owner).approve(this.diamond.address, to18('1000000000')); + await this.weth.connect(owner).approve(this.diamond.address, to18('1000000000')); + await this.weth.connect(user).approve(this.diamond.address, to18('1000000000')); + await this.weth.connect(user2).approve(this.diamond.address, to18('1000000000')); + + this.well = await deployBasin(true, undefined, false, true) + this.wellToken = await ethers.getContractAt("IERC20", this.well.address) + await this.wellToken.connect(owner).approve(BEANSTALK, ethers.constants.MaxUint256) + await this.bean.connect(owner).approve(BEANSTALK, ethers.constants.MaxUint256) + + await setEthUsdPrice('999.998018') + await setEthUsdcPrice('1000') + + console.log(`Well Address: ${this.well.address}`) - await this.usdc.mint(owner.address, to18('1000000000')); - await this.usdc.mint(user.address, to6('1000')); - await this.usdc.mint(user2.address, to6('1000')); - await this.usdc.connect(owner).approve(this.diamond.address, to18('1000000000')); - await this.usdc.connect(user).approve(this.diamond.address, to18('1000000000')); - await this.usdc.connect(user2).approve(this.diamond.address, to18('1000000000')); }); beforeEach(async function () { @@ -69,7 +84,7 @@ describe('Fertilize', function () { }); it('reverts if early Season', async function () { - await expect(this.fertilizer.connect(owner).addFertilizerOwner('1000', '1', '0')).to.be.revertedWith('SafeMath: subtraction overflow') + await expect(this.fertilizer.connect(owner).addFertilizerOwner('1', '1', '0')).to.be.revertedWith('SafeMath: subtraction overflow') }) describe("Get Humidity", async function () { @@ -110,7 +125,7 @@ describe('Fertilize', function () { describe('Add Fertilizer', async function () { describe('1 fertilizer', async function () { beforeEach(async function () { - this.result = await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') + this.result = await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') }) it("updates totals", async function () { @@ -124,15 +139,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('2')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('1866180825834066049') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('29438342344636187') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('1')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(lpBeansForUsdc('1')) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.001')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(lpBeansForUsdc('1')) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('2')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('1866180825834066049') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -151,8 +166,8 @@ describe('Fertilize', function () { describe('1 fertilizer twice', async function () { beforeEach(async function () { - await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') this.depositedBeans = beansForUsdc('1').add(beansForUsdc('1')) }) @@ -166,15 +181,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('3.999999')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('3732361651668132099') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('58876684689272374') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('2')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(lpBeansForUsdc('2')) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.002')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(lpBeansForUsdc('2')) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('3.999999')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('3732361651668132099') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -184,8 +199,8 @@ describe('Fertilize', function () { describe('2 fertilizers', async function () { beforeEach(async function () { - await this.fertilizer.connect(owner).addFertilizerOwner('0', '5', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.005'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') this.lpBeans = lpBeansForUsdc('5').add(lpBeansForUsdc('1')) }) @@ -200,15 +215,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('11.999999')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('11197084955004396299') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('176630054067817122') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('6')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.006')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('11.999999')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('11197084955004396299') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -216,18 +231,27 @@ describe('Fertilize', function () { expect(await this.fertilizer.getFertilizer(to6('6'))).to.be.equal('5') }) }) + + describe('Too much Fertilizer', async function () { + it("reverts", async function () { + expect( + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('1'), '0') + ).to.be.revertedWith("Fertilizer: No more fertilizer available") + }) + + }) }) describe('Sort fertilizer seasons', async function () { beforeEach(async function () { - await this.fertilizer.connect(owner).addFertilizerOwner('10000', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('6374', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('6274', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('9000', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('6174', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('10000', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('6374', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('6274', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('9000', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('6174', to18('0.001'), '0') await this.season.rewardToFertilizerE(to6('2.5')) - await this.fertilizer.connect(owner).addFertilizerOwner('7000', '1', '0') - await this.fertilizer.connect(owner).addFertilizerOwner('0', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('7000', to18('0.001'), '0') + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.001'), '0') }) it('properly sorts fertilizer', async function () { @@ -251,7 +275,7 @@ describe('Fertilize', function () { describe('1 mint', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100') }) @@ -266,15 +290,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('200')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('186618082583406604989') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('2943834234463618707') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('100')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.1')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('200')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('186618082583406604989') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -297,8 +321,8 @@ describe('Fertilize', function () { describe('2 mints', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('50', '0', EXTERNAL) - this.result = await this.fertilizer.connect(user).mintFertilizer('50', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100'); }) @@ -313,15 +337,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal('199999999') // Rounds down - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('186618082583406604989') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('2943834234463618707') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('100')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.1')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal('199999999') // Rounds down - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('186618082583406604989') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -344,10 +368,10 @@ describe('Fertilize', function () { describe("2 mint with season in between", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100').add(lpBeansForUsdc('100')) }) @@ -363,15 +387,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('450')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('373236165166813209979') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('5887668468927237414') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('200')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.2')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('400')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('373236165166813209979') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -399,10 +423,10 @@ describe('Fertilize', function () { describe("2 mint with same id", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6174') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100').add(lpBeansForUsdc('100')) }) @@ -418,15 +442,15 @@ describe('Fertilize', function () { it('updates token balances', async function () { expect(await this.bean.balanceOf(this.fertilizer.address)).to.be.equal(to6('450')) - expect(await this.beanMetapool.balanceOf(this.fertilizer.address)).to.be.equal('373236165166813209979') + expect(await this.well.balanceOf(this.fertilizer.address)).to.be.equal('5887668468927237414') - expect(await this.threeCurve.balanceOf(this.beanMetapool.address)).to.be.equal(to18('200')) - expect(await this.bean.balanceOf(this.beanMetapool.address)).to.be.equal(this.lpBeans) + expect(await this.weth.balanceOf(this.well.address)).to.be.equal(to18('0.2')) + expect(await this.bean.balanceOf(this.well.address)).to.be.equal(this.lpBeans) }) it('updates underlying balances', async function () { expect(await this.unripe.getTotalUnderlying(UNRIPE_BEAN)).to.be.equal(to6('400')) - expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal('373236165166813209979') + expect(await this.unripe.getTotalUnderlying(UNRIPE_LP)).to.be.equal(await this.well.balanceOf(this.fertilizer.address)) }) it('updates fertizer amount', async function () { @@ -453,11 +477,11 @@ describe('Fertilize', function () { describe("2 mint with same id and claim", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6174') await this.fertilizer.connect(user).claimFertilized([to6('3.5')], INTERNAL) - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) }) it('updates claims fertilized Beans', async function () { @@ -469,7 +493,7 @@ describe('Fertilize', function () { describe("Fertilize", async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) }) it('gets fertilizable', async function () { @@ -557,7 +581,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) @@ -586,7 +610,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) @@ -615,7 +639,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('200')) @@ -644,7 +668,7 @@ describe('Fertilize', function () { describe("Transfer", async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) }) describe("no fertilized", async function () { @@ -708,7 +732,7 @@ describe('Fertilize', function () { describe("Both some Beans", async function () { beforeEach(async function() { - this.result = await this.fertilizer.connect(user2).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('100')) await this.fert.connect(user).safeTransferFrom(user.address, user2.address, to6('2.5'), '50', ethers.constants.HashZero) }) @@ -735,7 +759,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) await this.fert.connect(user).safeBatchTransferFrom(user.address, user2.address, [to6('2.5'), to6('3.5')], ['50', '50'], ethers.constants.HashZero) }) @@ -763,11 +787,11 @@ describe('Fertilize', function () { describe("Both some Beans", async function () { beforeEach(async function() { - this.result = await this.fertilizer.connect(user2).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('400')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer('100', '0', EXTERNAL) - this.result = await this.fertilizer.connect(user2).mintFertilizer('100', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('300')) await this.fert.connect(user).safeBatchTransferFrom(user.address, user2.address, [to6('2.5'), to6('3.5')], ['50', '50'], ethers.constants.HashZero) }) From 92d2dafbd58d7a2984b71ddd321d2b1a23ce4da9 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:50:44 -0400 Subject: [PATCH 50/96] Add migrate function --- protocol/contracts/beanstalk/barn/UnripeFacet.sol | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 6cd0b3f345..764b5c598e 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -54,6 +54,7 @@ contract UnripeFacet is ReentrancyGuard { LibTransfer.From fromMode, LibTransfer.To toMode ) external payable nonReentrant returns (uint256 underlyingAmount) { + uint256 unripeSupply = IERC20(unripeToken).totalSupply(); amount = LibTransfer.burnToken(IBean(unripeToken), amount, msg.sender, fromMode); @@ -242,4 +243,16 @@ contract UnripeFacet is ReentrancyGuard { { return s.u[unripeToken].underlyingToken; } + + /////////////// UNDERLYING TOKEN MIGRATION ////////////////// + + function addMigratedUnderlying(address unripeToken, uint256 amount) external payable nonReentrant { + LibDiamond.enforceIsContractOwner(); + IERC20(s.u[unripeToken].underlyingToken).safeTransferFrom( + msg.sender, + address(this), + amount + ); + LibUnripe.incrementUnderlying(unripeToken, amount); + } } From 2f327c653bd36e67ae0f2ab47c7d27c500543a51 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:51:18 -0400 Subject: [PATCH 51/96] Use sync instead of add liquidity in Well convert --- .../contracts/libraries/Convert/LibWellConvert.sol | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/protocol/contracts/libraries/Convert/LibWellConvert.sol b/protocol/contracts/libraries/Convert/LibWellConvert.sol index a147e72438..a1cb7076b9 100644 --- a/protocol/contracts/libraries/Convert/LibWellConvert.sol +++ b/protocol/contracts/libraries/Convert/LibWellConvert.sol @@ -196,14 +196,10 @@ library LibWellConvert { require(maxBeans > 0, "Convert: P must be >= 1."); beansConverted = beans > maxBeans ? maxBeans : beans; IERC20[] memory tokens = IWell(well).tokens(); - uint256[] memory amounts = new uint256[](tokens.length); - amounts[beanIndex] = beansConverted; - C.bean().approve(well, beansConverted); - lp = IWell(well).addLiquidity( - amounts, - minLP, + C.bean().transfer(well, beans); + lp = IWell(well).sync( address(this), - block.timestamp + minLP ); } } From 59642b1f2e48d8fd6b907e1a565c487292c47372 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:51:56 -0400 Subject: [PATCH 52/96] Convert into/from Bean:Eth for Unripe assets --- .../libraries/Convert/LibUnripeConvert.sol | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/protocol/contracts/libraries/Convert/LibUnripeConvert.sol b/protocol/contracts/libraries/Convert/LibUnripeConvert.sol index 43824b8992..a493067178 100644 --- a/protocol/contracts/libraries/Convert/LibUnripeConvert.sol +++ b/protocol/contracts/libraries/Convert/LibUnripeConvert.sol @@ -5,7 +5,7 @@ pragma experimental ABIEncoderV2; import {C} from "contracts/C.sol"; import {IBean} from "contracts/interfaces/IBean.sol"; -import {LibCurveConvert} from "./LibCurveConvert.sol"; +import {LibWellConvert} from "./LibWellConvert.sol"; import {LibUnripe} from "../LibUnripe.sol"; import {LibConvertData} from "./LibConvertData.sol"; import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; @@ -39,10 +39,10 @@ library LibUnripeConvert { ( uint256 outUnderlyingAmount, uint256 inUnderlyingAmount - ) = LibCurveConvert.curveRemoveLPTowardsPeg( + ) = LibWellConvert._wellRemoveLiquidityTowardsPeg( LibUnripe.unripeToUnderlying(tokenIn, lp), minAmountOut, - C.CURVE_BEAN_METAPOOL + C.BEAN_ETH_WELL ); amountIn = LibUnripe.underlyingToUnripe(tokenIn, inUnderlyingAmount); @@ -78,10 +78,10 @@ library LibUnripeConvert { ( uint256 outUnderlyingAmount, uint256 inUnderlyingAmount - ) = LibCurveConvert.curveAddLiquidityTowardsPeg( + ) = LibWellConvert._wellAddLiquidityTowardsPeg( LibUnripe.unripeToUnderlying(tokenIn, beans), minAmountOut, - C.CURVE_BEAN_METAPOOL + C.BEAN_ETH_WELL ); amountIn = LibUnripe.underlyingToUnripe(tokenIn, inUnderlyingAmount); @@ -97,8 +97,8 @@ library LibUnripeConvert { } function beansToPeg() internal view returns (uint256 beans) { - uint256 underlyingBeans = LibCurveConvert.beansToPeg( - C.CURVE_BEAN_METAPOOL + uint256 underlyingBeans = LibWellConvert.beansToPeg( + C.BEAN_ETH_WELL ); beans = LibUnripe.underlyingToUnripe( C.UNRIPE_BEAN, @@ -107,8 +107,8 @@ library LibUnripeConvert { } function lpToPeg() internal view returns (uint256 lp) { - uint256 underlyingLP = LibCurveConvert.lpToPeg( - C.CURVE_BEAN_METAPOOL + uint256 underlyingLP = LibWellConvert.lpToPeg( + C.BEAN_ETH_WELL ); lp = LibUnripe.underlyingToUnripe(C.UNRIPE_LP, underlyingLP); } @@ -122,7 +122,7 @@ library LibUnripeConvert { C.UNRIPE_BEAN, amountIn ); - lp = LibCurveConvert.getLPAmountOut(C.CURVE_BEAN_METAPOOL, beans); + lp = LibWellConvert.getLPAmountOut(C.BEAN_ETH_WELL, beans); lp = LibUnripe .underlyingToUnripe(C.UNRIPE_LP, lp) .mul(LibUnripe.percentLPRecapped()) @@ -138,7 +138,7 @@ library LibUnripeConvert { C.UNRIPE_LP, amountIn ); - bean = LibCurveConvert.getBeanAmountOut(C.CURVE_BEAN_METAPOOL, lp); + bean = LibWellConvert.getBeanAmountOut(C.BEAN_ETH_WELL, lp); bean = LibUnripe .underlyingToUnripe(C.UNRIPE_BEAN, bean) .mul(LibUnripe.percentBeansRecapped()) From 2ec0e7a98e7ac7fdce136e7493656d3ebc9adfa6 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:53:42 -0400 Subject: [PATCH 53/96] Script and Helper function updates --- protocol/scripts/basin.js | 54 ++++++++++++++++-------------- protocol/scripts/impersonate.js | 14 ++++++-- protocol/test/EthUsdOracle.test.js | 34 +++---------------- protocol/test/WellBdv.test.js | 1 - protocol/test/WellConvert.test.js | 1 - protocol/utils/oracle.js | 38 +++++++++++++++++++++ 6 files changed, 82 insertions(+), 60 deletions(-) create mode 100644 protocol/utils/oracle.js diff --git a/protocol/scripts/basin.js b/protocol/scripts/basin.js index f98b7dfe98..6efb0dcfb6 100644 --- a/protocol/scripts/basin.js +++ b/protocol/scripts/basin.js @@ -37,15 +37,15 @@ async function deployBasinAndIntegrationBip(mock, bipAccount = undefined, basinA await bipBasinIntegration(mock, bipAccount); } -async function deployBasin(mock = true, accounts = undefined) { +async function deployBasin(mock = true, accounts = undefined, verbose = true, justDeploy = false) { - console.log("Deploying Basin...") + if (verbose) console.log("Deploying Basin...") let account = await getAccount(accounts, 'aquifer', AQUIFER_DEPLOYER); - const aquifer = await deployWellContractAtNonce('Aquifer', AQUIFER_DEPLOY_NONCE, [], account, true); + const aquifer = await deployWellContractAtNonce('Aquifer', AQUIFER_DEPLOY_NONCE, [], account, verbose); account = await getAccount(accounts, 'constantProduct2', CONSTANT_PRODUCT_2_DEPLOYER); - const constantProduct2 = await deployWellContractAtNonce('ConstantProduct2', CONSTANT_PRODUCT_2_DEPLOY_NONCE, [], account, true); + const constantProduct2 = await deployWellContractAtNonce('ConstantProduct2', CONSTANT_PRODUCT_2_DEPLOY_NONCE, [], account, verbose); account = await getAccount(accounts, 'multiFlowPump', MULTI_FLOW_PUMP_DEPLOYER); let multiFlowPump = await deployWellContractAtNonce('MultiFlowPump', MULTI_FLOW_PUMP_DEPLOY_NONCE, [ @@ -53,11 +53,11 @@ async function deployBasin(mock = true, accounts = undefined) { MULTI_FLOW_PUMP_MAX_PERCENT_DECREASE, MULTI_FLOW_PUMP_CAP_INTERVAL, MULTI_FLOW_PUMP_ALPHA - ], account, true); + ], account, verbose); account = await getAccount(accounts, 'wellImplementation', WELL_IMPLEMENTATION_DEPLOYER); const wellImplementation = await deployWellContractAtNonce('Well', WELL_IMPLEMENTATION_DEPLOY_NONCE, [], account, false); - console.log("Well Implementation Deployed at", wellImplementation.address); + if (verbose) console.log("Well Implementation Deployed at", wellImplementation.address); account = await getAccount(accounts, 'well', WELL_DEPLOYER); const immutableData = encodeWellImmutableData( @@ -88,11 +88,13 @@ async function deployBasin(mock = true, accounts = undefined) { await wellTxn.wait(); - console.log("Bean:Eth Well Deployed at:", well.address); + if (justDeploy) return well; - console.log(""); + if (verbose) console.log("Bean:Eth Well Deployed at:", well.address); - console.log("Adding Liquidity to Well...") + if (verbose) console.log(""); + + if (verbose) console.log("Adding Liquidity to Well...") account = await getAccount(accounts, 'addLiquidity', ADD_LIQUIDITY_ADDRESS); @@ -102,51 +104,51 @@ async function deployBasin(mock = true, accounts = undefined) { const ethUsdChainlinkAggregator = await ethers.getContractAt('MockChainlinkAggregator', ETH_USD_CHAINLINK_AGGREGATOR) const beanEthPrice = (await ethUsdChainlinkAggregator.latestRoundData()).answer; - console.log("Bean:Eth Price:", beanEthPrice.toString()); + if (verbose) console.log("Bean:Eth Price:", beanEthPrice.toString()); const amounts = [ toBN(INITIAL_BEAN_LIQUIDITY), toBN(INITIAL_BEAN_LIQUIDITY).mul(toX('1', 20)).div(beanEthPrice) ] - console.log("Bean Amount:", amounts[0].toString()); - console.log("Eth Amount:", amounts[1].toString()); + if (verbose) console.log("Bean Amount:", amounts[0].toString()); + if (verbose) console.log("Eth Amount:", amounts[1].toString()); - console.log(account.address) + if (verbose) console.log(account.address) - console.log("Approving.."); + if (verbose) onsole.log("Approving.."); await bean.connect(account).approve(well.address, amounts[0]); await weth.connect(account).approve(well.address, amounts[1]); - console.log("Wrapping Eth.."); + if (verbose) console.log("Wrapping Eth.."); await weth.connect(account).deposit({ value: amounts[1] }); - console.log('Adding Liquidity..') + if (verbose) console.log('Adding Liquidity..') const lpAmountOut = well.getAddLiquidityOut(amounts); let txn = await well.connect(account).addLiquidity(amounts, lpAmountOut, account.address, ethers.constants.MaxUint256); await txn.wait(); txn = await well.connect(account).addLiquidity([toBN('0'), toBN('0')], '0', account.address, ethers.constants.MaxUint256); await txn.wait(); - console.log('') + if (verbose) console.log('') const reserves = await well.getReserves(); - console.log("Well Statistics:") - console.log("Bean Reserve:", reserves[0].toString()); - console.log("Eth Reserve:", reserves[1].toString()); - console.log("LP Token Total Supply:", (await well.totalSupply()).toString()); + if (verbose) console.log("Well Statistics:") + if (verbose) console.log("Bean Reserve:", reserves[0].toString()); + if (verbose) console.log("Eth Reserve:", reserves[1].toString()); + if (verbose) console.log("LP Token Total Supply:", (await well.totalSupply()).toString()); - console.log('') + if (verbose) console.log('') - console.log("Pump Statistics:") + if (verbose) console.log("Pump Statistics:") const instantaneousReserves = await multiFlowPump.readInstantaneousReserves( well.address, "0x" ); - console.log("Instantaneous Bean Reserve:", instantaneousReserves[0].toString()); - console.log("Instantaneous WETH Reserve:", instantaneousReserves[1].toString()); + if (verbose) console.log("Instantaneous Bean Reserve:", instantaneousReserves[0].toString()); + if (verbose) console.log("Instantaneous WETH Reserve:", instantaneousReserves[1].toString()); - console.log('') + if (verbose) console.log('') } async function getAccount(accounts, key, mockAddress) { diff --git a/protocol/scripts/impersonate.js b/protocol/scripts/impersonate.js index f603ed405e..261a738ba9 100644 --- a/protocol/scripts/impersonate.js +++ b/protocol/scripts/impersonate.js @@ -281,6 +281,17 @@ async function beanEthWell() { ]); } +async function impersonateContract(contractName, deployAddress) { + contract = await (await ethers.getContractFactory(contractName)).deploy() + await contract.deployed() + const bytecode = await ethers.provider.getCode(contract.address) + await network.provider.send("hardhat_setCode", [ + deployAddress, + bytecode, + ]); + return await ethers.getContractAt(contractName, deployAddress) +} + async function ethUsdChainlinkAggregator() { let chainlinkAggregatorJson = fs.readFileSync(`./artifacts/contracts/mocks/chainlink/MockChainlinkAggregator.sol/MockChainlinkAggregator.json`); @@ -292,8 +303,6 @@ async function ethUsdChainlinkAggregator() { await ethUsdChainlinkAggregator.setDecimals(6) } - - exports.impersonateRouter = router exports.impersonateBean = bean exports.impersonateCurve = curve @@ -311,3 +320,4 @@ exports.impersonateEthUsdtUniswap = ethUsdtUniswap exports.impersonateBeanstalk = impersonateBeanstalk exports.impersonateEthUsdChainlinkAggregator = ethUsdChainlinkAggregator exports.impersonateBeanEthWell = beanEthWell +exports.impersonateContract = impersonateContract diff --git a/protocol/test/EthUsdOracle.test.js b/protocol/test/EthUsdOracle.test.js index 70018aef69..7413062d7d 100644 --- a/protocol/test/EthUsdOracle.test.js +++ b/protocol/test/EthUsdOracle.test.js @@ -1,35 +1,14 @@ const { expect } = require('chai'); const { deploy } = require('../scripts/deploy.js'); const { getAltBeanstalk, getBean } = require('../utils/contracts.js'); -const { ETH_USDC_UNISWAP_V3, ETH_USDT_UNISWAP_V3, WETH, ETH_USD_CHAINLINK_AGGREGATOR } = require('./utils/constants.js'); +const { ETH_USDC_UNISWAP_V3, ETH_USDT_UNISWAP_V3, WETH } = require('./utils/constants.js'); const { to6, to18 } = require('./utils/helpers.js'); const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot.js"); const { toBN } = require('../utils/helpers.js'); +const { setEthUsdcPrice, setEthUsdPrice, setEthUsdtPrice, setOracleFailure } = require('../utils/oracle.js'); let user, user2, owner; -let ethUsdcUniswapPool, ethUsdtUniswapPool, ethUsdChainlinkAggregator; - -async function setEthUsdcPrice(price) { - await ethUsdcUniswapPool.setOraclePrice(to6(price), 18); -} - -async function setEthUsdPrice(price) { - const block = await ethers.provider.getBlock("latest"); - await ethUsdChainlinkAggregator.addRound(to6(price), block.timestamp, block.timestamp, '1') -} - -async function setEthUsdtPrice(price) { - await ethUsdtUniswapPool.setOraclePrice(to18('1').div(toBN('1').add(price)), 6); -} - -async function printPrices() { - console.log(`CUSD Price: ${await season.getChainlinkEthUsdPrice()}`) - console.log(`USDT Price: ${await season.getEthUsdtPrice()}`) - console.log(`USDC Price: ${await season.getEthUsdcPrice()}`) - -} - async function setToSecondsAfterHour(seconds = 0) { const lastTimestamp = (await ethers.provider.getBlock('latest')).timestamp; const hourTimestamp = parseInt(lastTimestamp/3600 + 1) * 3600 + seconds @@ -53,11 +32,6 @@ describe('USD Oracle', function () { await setToSecondsAfterHour(0) await owner.sendTransaction({to: user.address, value: 0}) - ethUsdtUniswapPool = await ethers.getContractAt('MockUniswapV3Pool', ETH_USDT_UNISWAP_V3); - ethUsdChainlinkAggregator = await ethers.getContractAt('MockChainlinkAggregator', ETH_USD_CHAINLINK_AGGREGATOR) - await ethUsdChainlinkAggregator.setDecimals(6) - ethUsdcUniswapPool = await ethers.getContractAt('MockUniswapV3Pool', ETH_USDC_UNISWAP_V3); - await setEthUsdPrice('10000') await setEthUsdcPrice('10000') await setEthUsdtPrice('10000') @@ -171,13 +145,13 @@ describe('USD Oracle', function () { describe("Handles Uniswap Oracle Failure", async function () { it ('succeeds when ETH/USDT call fails', async function () { - await ethUsdtUniswapPool.setOracleFailure(true) + await setOracleFailure(true, ETH_USDT_UNISWAP_V3) await setEthUsdcPrice('10050') await checkPriceWithError('10025') }) it ('succeeds when ETH/USDC call fails', async function () { - await ethUsdcUniswapPool.setOracleFailure(true) + await setOracleFailure(true, ETH_USDC_UNISWAP_V3) await checkPriceWithError('10000') }) }) diff --git a/protocol/test/WellBdv.test.js b/protocol/test/WellBdv.test.js index c0186b91f4..69a45885f8 100644 --- a/protocol/test/WellBdv.test.js +++ b/protocol/test/WellBdv.test.js @@ -34,7 +34,6 @@ describe('Well BDV', function () { await this.well.setTokens([BEAN, WETH]) this.pump.setInstantaneousReserves([to18('1'), to18('1')]) await whitelistWell(this.well.address, '10000', to6('4')) - }); beforeEach(async function () { diff --git a/protocol/test/WellConvert.test.js b/protocol/test/WellConvert.test.js index a79f2935e4..19764200d3 100644 --- a/protocol/test/WellConvert.test.js +++ b/protocol/test/WellConvert.test.js @@ -31,7 +31,6 @@ describe('Well Convert', function () { await this.wellToken.connect(owner).approve(this.beanstalk.address, ethers.constants.MaxUint256) await this.bean.connect(owner).approve(this.beanstalk.address, ethers.constants.MaxUint256) - await setEthUsdPrice('999.998018') await setEthUsdcPrice('1000') await setEthUsdtPrice('1000') diff --git a/protocol/utils/oracle.js b/protocol/utils/oracle.js new file mode 100644 index 0000000000..25e8f75fa9 --- /dev/null +++ b/protocol/utils/oracle.js @@ -0,0 +1,38 @@ +const { ETH_USDC_UNISWAP_V3, ETH_USD_CHAINLINK_AGGREGATOR, ETH_USDT_UNISWAP_V3, BEANSTALK } = require("../test/utils/constants"); +const { to18, to6 } = require("../test/utils/helpers"); +const { toBN } = require("./helpers"); + +async function setEthUsdcPrice(price) { + const ethUsdcUniswapPool = await ethers.getContractAt('MockUniswapV3Pool', ETH_USDC_UNISWAP_V3); + await ethUsdcUniswapPool.setOraclePrice(to6(price), 18); +} + +async function setEthUsdPrice(price) { + const ethUsdChainlinkAggregator = await ethers.getContractAt('MockChainlinkAggregator', ETH_USD_CHAINLINK_AGGREGATOR) + const block = await ethers.provider.getBlock("latest"); + await ethUsdChainlinkAggregator.addRound(to6(price), block.timestamp, block.timestamp, '1') +} + +async function setEthUsdtPrice(price) { + const ethUsdtUniswapPool = await ethers.getContractAt('MockUniswapV3Pool', ETH_USDT_UNISWAP_V3); + await ethUsdtUniswapPool.setOraclePrice(to18('1').div(toBN('1').add(price)), 6); +} + +async function printPrices() { + const season = await ethers.getContractAt('MockSeasonFacet', BEANSTALK); + console.log(`CUSD Price: ${await season.getChainlinkEthUsdPrice()}`) + console.log(`USDT Price: ${await season.getEthUsdtPrice()}`) + console.log(`USDC Price: ${await season.getEthUsdcPrice()}`) + console.log(`USD Price: ${await season.getEthUsdPrice()}`) +} + +async function setOracleFailure(bool, poolAddress) { + const pool = await ethers.getContractAt('MockUniswapV3Pool', poolAddress); + await pool.setOracleFailure(bool); +} + +exports.setEthUsdcPrice = setEthUsdcPrice; +exports.setEthUsdPrice = setEthUsdPrice; +exports.setEthUsdtPrice = setEthUsdtPrice; +exports.printPrices = printPrices; +exports.setOracleFailure = setOracleFailure; \ No newline at end of file From 8ed809934a3c501a536f2778c345b81cc3161e41 Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:54:07 -0400 Subject: [PATCH 54/96] Update Unripe BDV Function --- .../contracts/beanstalk/silo/BDVFacet.sol | 2 +- protocol/test/bdv.test.js | 64 +++++++++---------- 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/protocol/contracts/beanstalk/silo/BDVFacet.sol b/protocol/contracts/beanstalk/silo/BDVFacet.sol index 466bc615ab..84334341af 100644 --- a/protocol/contracts/beanstalk/silo/BDVFacet.sol +++ b/protocol/contracts/beanstalk/silo/BDVFacet.sol @@ -37,7 +37,7 @@ contract BDVFacet { */ function unripeLPToBDV(uint256 amount) public view returns (uint256) { amount = LibUnripe.unripeToUnderlying(C.UNRIPE_LP, amount); - amount = LibBeanMetaCurve.bdv(amount); + amount = LibWellBdv.bdv(C.BEAN_ETH_WELL, amount); return amount; } diff --git a/protocol/test/bdv.test.js b/protocol/test/bdv.test.js index 67c9978578..319bb4b289 100644 --- a/protocol/test/bdv.test.js +++ b/protocol/test/bdv.test.js @@ -1,8 +1,11 @@ const { expect } = require('chai'); const { deploy } = require('../scripts/deploy.js') const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); -const { BEAN, THREE_POOL, BEAN_3_CURVE, UNRIPE_LP, UNRIPE_BEAN, ZERO_ADDRESS } = require('./utils/constants'); -const { to18, to6 } = require('./utils/helpers.js') +const { BEAN, THREE_POOL, BEAN_3_CURVE, UNRIPE_LP, UNRIPE_BEAN, ZERO_ADDRESS, WETH, BEAN_ETH_WELL } = require('./utils/constants'); +const { to18, to6 } = require('./utils/helpers.js'); +const { deployMockPump, getWellContractFactory, whitelistWell } = require('../utils/well.js'); +const { impersonateContract } = require('../scripts/impersonate.js'); +const { toBN } = require('../utils/helpers.js'); let user,user2,owner; let userAddress, ownerAddress, user2Address; const ZERO_BYTES = ethers.utils.formatBytes32String('0x0') @@ -11,6 +14,7 @@ let snapshotId; describe('BDV', function () { before(async function () { + [owner,user,user2] = await ethers.getSigners(); userAddress = user.address; user2Address = user2.address; @@ -22,34 +26,26 @@ describe('BDV', function () { this.silo = await ethers.getContractAt('MockSiloFacet', this.diamond.address) this.convert = await ethers.getContractAt('ConvertFacet', this.diamond.address) this.bean = await ethers.getContractAt('MockToken', BEAN); + this.bdv = await ethers.getContractAt('BDVFacet', this.diamond.address) - this.siloToken = await ethers.getContractFactory("MockToken"); - this.siloToken = await this.siloToken.deploy("Silo", "SILO") - await this.siloToken.deployed() - - await this.silo.mockWhitelistToken( - this.siloToken.address, - this.silo.interface.getSighash("mockBDV(uint256 amount)"), - '10000', - 1e6 //aka "1 seed" - ); + this.well = await impersonateContract('MockSetComponentsWell', BEAN_ETH_WELL) await this.season.siloSunrise(0); await this.bean.mint(userAddress, '1000000000'); await this.bean.mint(ownerAddress, '1000000000'); - await this.siloToken.connect(user).approve(this.silo.address, '100000000000'); + await this.well.connect(user).approve(this.silo.address, '100000000000'); await this.bean.connect(user).approve(this.silo.address, '100000000000'); await this.bean.connect(owner).approve(this.silo.address, '100000000000'); - await this.siloToken.mint(userAddress, '10000'); - await this.siloToken.mint(ownerAddress, to18('1000')); - await this.siloToken.approve(this.silo.address, to18('1000')); + await this.well.mint(userAddress, '10000'); + await this.well.mint(ownerAddress, to18('1000')); + await this.well.approve(this.silo.address, to18('1000')); this.unripe = await ethers.getContractAt('MockUnripeFacet', this.silo.address) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) await this.unripeLP.connect(user).mint(userAddress, to18('10000')) await this.unripeLP.connect(user).approve(this.silo.address, to18('10000')) - await this.unripe.addUnripeToken(UNRIPE_LP, this.siloToken.address, ZERO_BYTES) + await this.unripe.addUnripeToken(UNRIPE_LP, this.well.address, ZERO_BYTES) await this.unripe.connect(owner).addUnderlying( UNRIPE_LP, to18('1000') @@ -114,29 +110,29 @@ describe('BDV', function () { describe("Unripe LP BDV", async function () { before(async function () { - this.threePool = await ethers.getContractAt('Mock3Curve', THREE_POOL); - await this.threePool.set_virtual_price(to18('1')); - this.beanThreeCurve = await ethers.getContractAt('MockMeta3Curve', BEAN_3_CURVE); - await this.beanThreeCurve.set_supply(to18('2000000')); - await this.beanThreeCurve.set_A_precise('1000'); - await this.beanThreeCurve.set_virtual_price(to18('1')); - await this.beanThreeCurve.set_balances([ - to6('1000000'), - to18('1000000') - ]); - await this.beanThreeCurve.set_balances([ - to6('1200000'), - to18('1000000') - ]); + this.pump = await deployMockPump() + + this.wellFunction = await (await getWellContractFactory('ConstantProduct2')).deploy() + await this.wellFunction.deployed() + + await this.well.setPumps([[this.pump.address, '0x']]) + await this.well.setWellFunction([this.wellFunction.address, '0x']) + await this.well.setTokens([BEAN, WETH]) + this.pump.setInstantaneousReserves([to18('1'), to18('1')]) + await whitelistWell(this.well.address, '10000', to6('4')) }); it("properly checks bdv", async function () { - expect(await this.silo.bdv(UNRIPE_LP, to18('2000'))).to.equal(to6('200')); + const wellBdv = await this.silo.bdv(this.well.address, to18('200')) + expect(await this.bdv.unripeLPToBDV(to18('2000'))).to.eq(wellBdv); + expect(await this.silo.bdv(UNRIPE_LP, to18('2000'))).to.equal(wellBdv); }) it("properly checks bdv", async function () { - await this.threePool.set_virtual_price(to18('1.02')); - expect(await this.silo.bdv(UNRIPE_LP, to18('20'))).to.equal('1998191'); + this.pump.setInstantaneousReserves([to18('1.02'), to18('1')]) + const wellBdv = await this.silo.bdv(this.well.address, to18('2')) + expect(await this.bdv.unripeLPToBDV(to18('20'))).to.equal(wellBdv); + expect(await this.silo.bdv(UNRIPE_LP, to18('20'))).to.equal(wellBdv); }) }) From 6998f47728efc928946fcae4e748d7e34760257a Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 12:54:20 -0400 Subject: [PATCH 55/96] Add migration init script --- .../init/InitMigrateUnripeBean3CrvToEth.sol | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol diff --git a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol new file mode 100644 index 0000000000..6ea7ee6be5 --- /dev/null +++ b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol @@ -0,0 +1,31 @@ +/* + SPDX-License-Identifier: MIT +*/ + +pragma solidity =0.7.6; +pragma experimental ABIEncoderV2; + +import {AppStorage} from "contracts/beanstalk/AppStorage.sol"; +import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import {C} from "contracts/C.sol"; +import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; +import {LibUnripe} from "contracts/libraries/LibUnripe.sol"; + +/** + * Initializes the Migration of the Unripe LP underlying tokens from Bean:3Crv to Bean:Eth. + */ +contract InitMigrateUnripeBean3CrvToEth { + using SafeERC20 for IERC20; + + AppStorage internal s; + + function init() external { + uint256 balanceOfUnderlying = s.u[C.UNRIPE_LP].balanceOfUnderlying; + IERC20(s.u[C.UNRIPE_LP].underlyingToken).safeTransfer( + LibDiamond.diamondStorage().contractOwner, + balanceOfUnderlying + ); + LibUnripe.decrementUnderlying(C.UNRIPE_LP, balanceOfUnderlying); + s.u[C.UNRIPE_LP].underlyingToken = C.BEAN_ETH_WELL; + } +} \ No newline at end of file From cca2825bee94a0d75231c9fc22c123e2c254636b Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 13:04:55 -0400 Subject: [PATCH 56/96] fix build --- .../contracts/beanstalk/barn/FertilizerFacet.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index fdcc4179f6..ec0737c7de 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -49,9 +49,9 @@ contract FertilizerFacet { * Can be used to help calculate `minFertilizerOut` in `mintFertilizer` */ function getMintFertilizerOut( - uint128 wethAmountIn + uint256 wethAmountIn ) external view returns (uint256 fertilizerAmountOut) { - fertilizerAmountOut = amount.mul( + fertilizerAmountOut = wethAmountIn.mul( LibEthUsdOracle.getEthUsdPrice() ).div(1e24); } @@ -71,15 +71,15 @@ contract FertilizerFacet { LibTransfer.From mode ) external payable returns (uint256 fertilizerAmountOut) { - amount = LibTransfer.receiveToken( + wethAmountIn = LibTransfer.receiveToken( IERC20(C.WETH), - uint256(amount), + uint256(wethAmountIn), msg.sender, mode ); // return value <= amount, so downcasting is safe. // Convert from Ether amount with 18 decimals to USD amount with 0 decimals. - fertilizerAmountOut = amount.mul( + fertilizerAmountOut = wethAmountIn.mul( LibEthUsdOracle.getEthUsdPrice() ).div(1e24); @@ -90,7 +90,7 @@ contract FertilizerFacet { uint128 id = LibFertilizer.addFertilizer( uint128(s.season.current), - amount, + wethAmountIn, fertilizerAmountOut, minLP ); From cafa651724db5c0cb4c6aefb7b9104176f8928ac Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 5 Sep 2023 14:56:19 -0400 Subject: [PATCH 57/96] rename init, update tests/scripts --- ...=> InitMigrateUnripeBean3CrvToBeanEth.sol} | 2 +- protocol/scripts/bips.js | 26 +++++++ protocol/scripts/impersonate.js | 14 +--- protocol/test/Fertilizer.test.js | 38 +++++----- protocol/test/SiloEnroot.test.js | 23 +++---- protocol/test/Stem.test.js | 2 +- protocol/test/beanstalkPrice.test.js | 2 +- protocol/utils/well.js | 69 ++++++++++++------- 8 files changed, 104 insertions(+), 72 deletions(-) rename protocol/contracts/beanstalk/init/{InitMigrateUnripeBean3CrvToEth.sol => InitMigrateUnripeBean3CrvToBeanEth.sol} (95%) diff --git a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol similarity index 95% rename from protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol rename to protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol index 6ea7ee6be5..8b1d77b910 100644 --- a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToEth.sol +++ b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol @@ -14,7 +14,7 @@ import {LibUnripe} from "contracts/libraries/LibUnripe.sol"; /** * Initializes the Migration of the Unripe LP underlying tokens from Bean:3Crv to Bean:Eth. */ -contract InitMigrateUnripeBean3CrvToEth { +contract InitMigrateUnripeBean3CrvToBeanEth { using SafeERC20 for IERC20; AppStorage internal s; diff --git a/protocol/scripts/bips.js b/protocol/scripts/bips.js index 4d9faefdd2..c40351a4a1 100644 --- a/protocol/scripts/bips.js +++ b/protocol/scripts/bips.js @@ -144,6 +144,31 @@ async function bip34(mock = true, account = undefined) { verify: false }); } +async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefined, verbose = true) { + if (account == undefined) { + account = await impersonateBeanstalkOwner(); + await mintEth(account.address); + } + + await upgradeWithNewFacets({ + diamondAddress: BEANSTALK, + facetNames: [ + "UnripeFacet", + "FertilizerFacet", + "BDVFacet", + "ConvertFacet", + "ConvertGettersFacet" + ], + initFacetName: "InitMigrateUnripeBean3CrvToBeanEth", + selectorsToRemove: [ '0x0bfca7e3' ], + bip: false, + object: !mock, + verbose: true, + account: account, + verify: false + }); + +} exports.bip29 = bip29 exports.bip30 = bip30 @@ -151,3 +176,4 @@ exports.bip34 = bip34 exports.bipNewSilo = bipNewSilo exports.bipBasinIntegration = bipBasinIntegration exports.mockBeanstalkAdmin = mockBeanstalkAdmin +exports.bipMigrateUnripeBean3CrvToBeanEth = bipMigrateUnripeBean3CrvToBeanEth diff --git a/protocol/scripts/impersonate.js b/protocol/scripts/impersonate.js index 261a738ba9..93aed6ab23 100644 --- a/protocol/scripts/impersonate.js +++ b/protocol/scripts/impersonate.js @@ -24,10 +24,8 @@ const { ETH_USDC_UNISWAP_V3, ETH_USDT_UNISWAP_V3, USDT, - ETH_USD_CHAINLINK_AGGREGATOR, - BEAN_ETH_WELL + ETH_USD_CHAINLINK_AGGREGATOR } = require('../test/utils/constants'); -const { deployWell } = require('../utils/well.js'); const { impersonateSigner, mintEth } = require('../utils'); const { getSigner } = '../utils' @@ -272,15 +270,6 @@ async function ethUsdtUniswap() { ]); } -async function beanEthWell() { - const well = await deployWell([BEAN, WETH]); - const bytecode = await ethers.provider.getCode(well.address) - await network.provider.send("hardhat_setCode", [ - BEAN_ETH_WELL, - bytecode, - ]); -} - async function impersonateContract(contractName, deployAddress) { contract = await (await ethers.getContractFactory(contractName)).deploy() await contract.deployed() @@ -319,5 +308,4 @@ exports.impersonateEthUsdcUniswap = ethUsdcUniswap exports.impersonateEthUsdtUniswap = ethUsdtUniswap exports.impersonateBeanstalk = impersonateBeanstalk exports.impersonateEthUsdChainlinkAggregator = ethUsdChainlinkAggregator -exports.impersonateBeanEthWell = beanEthWell exports.impersonateContract = impersonateContract diff --git a/protocol/test/Fertilizer.test.js b/protocol/test/Fertilizer.test.js index 4519aef102..adab06a69c 100644 --- a/protocol/test/Fertilizer.test.js +++ b/protocol/test/Fertilizer.test.js @@ -275,7 +275,7 @@ describe('Fertilize', function () { describe('1 mint', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100') }) @@ -321,8 +321,8 @@ describe('Fertilize', function () { describe('2 mints', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', EXTERNAL) - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.05'), '0', '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100'); }) @@ -368,10 +368,10 @@ describe('Fertilize', function () { describe("2 mint with season in between", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100').add(lpBeansForUsdc('100')) }) @@ -423,10 +423,10 @@ describe('Fertilize', function () { describe("2 mint with same id", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6174') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) this.lpBeans = lpBeansForUsdc('100').add(lpBeansForUsdc('100')) }) @@ -477,11 +477,11 @@ describe('Fertilize', function () { describe("2 mint with same id and claim", async function () { beforeEach(async function () { await this.season.teleportSunrise('6074') - await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('50')) await this.season.teleportSunrise('6174') await this.fertilizer.connect(user).claimFertilized([to6('3.5')], INTERNAL) - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) }) it('updates claims fertilized Beans', async function () { @@ -493,7 +493,7 @@ describe('Fertilize', function () { describe("Fertilize", async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) }) it('gets fertilizable', async function () { @@ -581,7 +581,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) @@ -610,7 +610,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) @@ -639,7 +639,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.fertilizer.connect(user).claimFertilized([to6('2.5')], EXTERNAL) await this.season.rewardToFertilizerE(to6('200')) @@ -668,7 +668,7 @@ describe('Fertilize', function () { describe("Transfer", async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) }) describe("no fertilized", async function () { @@ -732,7 +732,7 @@ describe('Fertilize', function () { describe("Both some Beans", async function () { beforeEach(async function() { - this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('100')) await this.fert.connect(user).safeTransferFrom(user.address, user2.address, to6('2.5'), '50', ethers.constants.HashZero) }) @@ -759,7 +759,7 @@ describe('Fertilize', function () { beforeEach(async function() { await this.season.rewardToFertilizerE(to6('200')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('150')) await this.fert.connect(user).safeBatchTransferFrom(user.address, user2.address, [to6('2.5'), to6('3.5')], ['50', '50'], ethers.constants.HashZero) }) @@ -787,11 +787,11 @@ describe('Fertilize', function () { describe("Both some Beans", async function () { beforeEach(async function() { - this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('400')) await this.season.teleportSunrise('6474') - this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', EXTERNAL) - this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', EXTERNAL) + this.result = await this.fertilizer.connect(user).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) + this.result = await this.fertilizer.connect(user2).mintFertilizer(to18('0.1'), '0', '0', EXTERNAL) await this.season.rewardToFertilizerE(to6('300')) await this.fert.connect(user).safeBatchTransferFrom(user.address, user2.address, [to6('2.5'), to6('3.5')], ['50', '50'], ethers.constants.HashZero) }) diff --git a/protocol/test/SiloEnroot.test.js b/protocol/test/SiloEnroot.test.js index dd3a549217..dbe618ce68 100644 --- a/protocol/test/SiloEnroot.test.js +++ b/protocol/test/SiloEnroot.test.js @@ -1,11 +1,11 @@ const { expect } = require("chai"); const { deploy } = require("../scripts/deploy.js"); -const { readPrune, toBN, signSiloDepositTokenPermit, signSiloDepositTokensPermit, getBean } = require("../utils"); -const { getAltBeanstalk } = require("../utils/contracts.js"); -const { EXTERNAL, INTERNAL, INTERNAL_EXTERNAL, INTERNAL_TOLERANT } = require("./utils/balances.js"); -const { BEAN, THREE_POOL, BEAN_3_CURVE, UNRIPE_LP, UNRIPE_BEAN, THREE_CURVE } = require("./utils/constants"); -const { to18, to6, toStalk, toBean } = require("./utils/helpers.js"); +const { readPrune, toBN, } = require("../utils"); +const { EXTERNAL } = require("./utils/balances.js"); +const { BEAN, BEAN_3_CURVE, UNRIPE_LP, UNRIPE_BEAN, THREE_CURVE, BEAN_ETH_WELL, WETH } = require("./utils/constants"); +const { to18, to6, toStalk } = require("./utils/helpers.js"); const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); +const { impersonateMockWell } = require("../utils/well.js"); const ZERO_BYTES = ethers.utils.formatBytes32String("0x0"); let user, user2, owner; @@ -47,13 +47,8 @@ describe("Silo Enroot", function () { await this.season.teleportSunrise(ENROOT_FIX_SEASON) - this.threeCurve = await ethers.getContractAt('MockToken', THREE_CURVE); - this.beanMetapool = await ethers.getContractAt('IMockCurvePool', BEAN_3_CURVE); - await this.beanMetapool.set_supply(ethers.utils.parseUnits('2000000', 6)); - await this.beanMetapool.set_balances([ - ethers.utils.parseUnits('1000000',6), - ethers.utils.parseEther('1000000') - ]); + const [well, pump, wellFunction] = await impersonateMockWell(pumpBalances = [to6('10000'), to18('10')]); + this.well = well; this.pump = pump; this.wellFunction = wellFunction; const SiloToken = await ethers.getContractFactory("MockToken"); this.siloToken = await SiloToken.deploy("Silo", "SILO"); @@ -265,12 +260,12 @@ describe("Silo Enroot", function () { it('properly updates the total balances', async function () { expect(await this.silo.getTotalDeposited(UNRIPE_LP)).to.eq(to6('20')); - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('3.7120352584')); + expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('234.7639163944')); expect(await this.silo.balanceOfSeeds(userAddress)).to.eq('0'); }); it('properly updates the user balance', async function () { - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('3.7120352584')); + expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('234.7639163944')); expect(await this.silo.balanceOfSeeds(userAddress)).to.eq('0'); }); diff --git a/protocol/test/Stem.test.js b/protocol/test/Stem.test.js index cda2fb03c1..381975a3c7 100644 --- a/protocol/test/Stem.test.js +++ b/protocol/test/Stem.test.js @@ -34,7 +34,7 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { console.log('forking error in Silo V3: Grown Stalk Per Bdv:'); console.log(error); return - }4 + } const signer = await impersonateBeanstalkOwner() await mintEth(signer.address); diff --git a/protocol/test/beanstalkPrice.test.js b/protocol/test/beanstalkPrice.test.js index 732a44c829..cbae75286c 100644 --- a/protocol/test/beanstalkPrice.test.js +++ b/protocol/test/beanstalkPrice.test.js @@ -7,7 +7,7 @@ const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); const { deployWell, setReserves, whitelistWell } = require('../utils/well.js'); const { setEthUsdPrice, setEthUsdcPrice, setEthUsdtPrice } = require('../scripts/usdOracle.js'); const { getBeanstalk } = require('../utils/contracts.js'); -const { impersonateBeanEthWell } = require('../scripts/impersonate.js') +const { impersonateBeanEthWell } = require('../utils/well.js') const fs = require('fs'); let user, user2, owner; diff --git a/protocol/utils/well.js b/protocol/utils/well.js index da72021ea1..c13745e162 100644 --- a/protocol/utils/well.js +++ b/protocol/utils/well.js @@ -2,9 +2,9 @@ const fs = require('fs'); const { BEAN, WETH, BEANSTALK_PUMP, BEAN_ETH_WELL } = require('../test/utils/constants'); const { to6, to18 } = require('../test/utils/helpers'); const { getBeanstalk } = require('./contracts'); -const { mintEth } = require('./mint'); const { impersonateBeanstalkOwner } = require('./signer'); const { increaseToNonce } = require('../scripts/contracts'); +const { impersonateContract } = require('../scripts/impersonate'); const BASE_STRING = './node_modules/@beanstalk/wells/out'; @@ -38,7 +38,7 @@ async function deployWellContract(name, arguments = [], account = undefined, ver return contract; } -async function deployMockToken(name="MockToken", symbol="MOCK") { +async function deployMockToken(name = "MockToken", symbol = "MOCK") { const MockToken = await ethers.getContractFactory('MockToken'); const mockToken = await MockToken.deploy(name, symbol); await mockToken.deployed(); @@ -63,7 +63,7 @@ function encodeWellImmutableData( ] ) } - + immutableData = ethers.utils.solidityPack( [ 'address', // aquifer address @@ -75,15 +75,15 @@ function encodeWellImmutableData( 'bytes', // well function data (bytes) 'bytes' // packed pumps (bytes) ], [ - aquifer, // aquifer address - tokens.length, // number of tokens - wellFunction.target, // well function address - wellFunction.length, // well function data length - pumps.length, // number of pumps - tokens, // tokens array - wellFunction.data, // well function data (bytes) - packedPumps // packed pumps (bytes) - ] + aquifer, // aquifer address + tokens.length, // number of tokens + wellFunction.target, // well function address + wellFunction.length, // well function data length + pumps.length, // number of pumps + tokens, // tokens array + wellFunction.data, // well function data (bytes) + packedPumps // packed pumps (bytes) + ] ); return immutableData } @@ -107,7 +107,7 @@ async function deployWell(tokens, verbose = false, salt = ethers.constants.HashZ aquifer.address, tokens, { target: wellFunction.address, data: '0x', length: 0 }, - [{target: pump.address, data: '0x', length: 0 }] + [{ target: pump.address, data: '0x', length: 0 }] ) const initData = await encodeInitFunctionCall(); @@ -181,6 +181,27 @@ async function setReserves(account, well, amounts) { } } +async function impersonateBeanEthWell() { + const well = await deployWell([BEAN, WETH]); + const bytecode = await ethers.provider.getCode(well.address) + await network.provider.send("hardhat_setCode", [ + BEAN_ETH_WELL, + bytecode, + ]); +} + +async function impersonateMockWell(pumpBalances = [to18('1'), to18('1')]) { + well = await impersonateContract('MockSetComponentsWell', BEAN_ETH_WELL) + pump = await deployMockPump() + wellFunction = await (await getWellContractFactory('ConstantProduct2')).deploy() + await well.setPumps([[this.pump.address, '0x']]) + await well.setWellFunction([this.wellFunction.address, '0x']) + await well.setTokens([BEAN, WETH]) + pump.setInstantaneousReserves(pumpBalances) + await whitelistWell(this.well.address, '10000', to6('4')) + return [well, pump, wellFunction] +} + async function whitelistWell(wellAddress, stalk, stalkEarnedPerSeason) { const beanstalk = await getBeanstalk() @@ -199,24 +220,24 @@ async function deployMockPump() { pump = await (await ethers.getContractFactory('MockPump')).deploy() await pump.deployed() await network.provider.send("hardhat_setCode", [ - BEANSTALK_PUMP, - await ethers.provider.getCode(pump.address), + BEANSTALK_PUMP, + await ethers.provider.getCode(pump.address), ]); return await ethers.getContractAt('MockPump', BEANSTALK_PUMP) } async function deployMultiFlowPump() { pump = await (await getWellContractFactory('MultiFlowPump')).deploy( - '0x3ffe0000000000000000000000000000', // 0.5 - '0x3ffd555555555555553cbcd83d925070', // 0.333333333333333333 - 12, - '0x3ffecccccccccccccccccccccccccccc' // 0.9 + '0x3ffe0000000000000000000000000000', // 0.5 + '0x3ffd555555555555553cbcd83d925070', // 0.333333333333333333 + 12, + '0x3ffecccccccccccccccccccccccccccc' // 0.9 ) await pump.deployed() await network.provider.send("hardhat_setCode", [ - BEANSTALK_PUMP, - await ethers.provider.getCode(pump.address), + BEANSTALK_PUMP, + await ethers.provider.getCode(pump.address), ]); return await getWellContractAt('MultiFlowPump', BEANSTALK_PUMP) } @@ -231,7 +252,7 @@ async function deployMockWell() { await network.provider.send("hardhat_setCode", [ BEAN_ETH_WELL, await ethers.provider.getCode(well.address), - ]); + ]); well = await ethers.getContractAt('MockSetComponentsWell', BEAN_ETH_WELL) await well.init() @@ -260,4 +281,6 @@ exports.deployMockWell = deployMockWell exports.deployMockPump = deployMockPump exports.deployWellContract = deployWellContract exports.deployWellContractAtNonce = deployWellContractAtNonce -exports.encodeWellImmutableData = encodeWellImmutableData \ No newline at end of file +exports.encodeWellImmutableData = encodeWellImmutableData +exports.impersonateMockWell = impersonateMockWell +exports.impersonateBeanEthWell = impersonateBeanEthWell \ No newline at end of file From d86a0f054380563fb4ed669d6a38d7f20a051cc4 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:39:53 -0400 Subject: [PATCH 58/96] remove extra line --- protocol/contracts/beanstalk/barn/UnripeFacet.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 764b5c598e..74bca8ba5a 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -54,7 +54,6 @@ contract UnripeFacet is ReentrancyGuard { LibTransfer.From fromMode, LibTransfer.To toMode ) external payable nonReentrant returns (uint256 underlyingAmount) { - uint256 unripeSupply = IERC20(unripeToken).totalSupply(); amount = LibTransfer.burnToken(IBean(unripeToken), amount, msg.sender, fromMode); From 1d72413a4f26f23998a7d1e09e980c5e9c3034ed Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:40:03 -0400 Subject: [PATCH 59/96] update abi --- protocol/abi/Beanstalk.json | 56 ++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/protocol/abi/Beanstalk.json b/protocol/abi/Beanstalk.json index 36db529a39..1e59bd6d06 100644 --- a/protocol/abi/Beanstalk.json +++ b/protocol/abi/Beanstalk.json @@ -128,6 +128,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "unripeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "addMigratedUnderlying", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -800,6 +818,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "wethAmountIn", + "type": "uint256" + } + ], + "name": "getMintFertilizerOut", + "outputs": [ + { + "internalType": "uint256", + "name": "fertilizerAmountOut", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -835,9 +872,14 @@ { "inputs": [ { - "internalType": "uint128", - "name": "amount", - "type": "uint128" + "internalType": "uint256", + "name": "wethAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minFertilizerOut", + "type": "uint256" }, { "internalType": "uint256", @@ -851,7 +893,13 @@ } ], "name": "mintFertilizer", - "outputs": [], + "outputs": [ + { + "internalType": "uint256", + "name": "fertilizerAmountOut", + "type": "uint256" + } + ], "stateMutability": "payable", "type": "function" }, From ec44f701ce2d1926379c129c0cc3df9838138846 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:40:16 -0400 Subject: [PATCH 60/96] update verbose flag --- protocol/scripts/bips.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/scripts/bips.js b/protocol/scripts/bips.js index c40351a4a1..07db151aaf 100644 --- a/protocol/scripts/bips.js +++ b/protocol/scripts/bips.js @@ -163,7 +163,7 @@ async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefine selectorsToRemove: [ '0x0bfca7e3' ], bip: false, object: !mock, - verbose: true, + verbose: verbose, account: account, verify: false }); From 11f9b2eef3a5c827a23f6671f4d7970141caeb42 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:40:35 -0400 Subject: [PATCH 61/96] update mint eth amount --- protocol/utils/mint.js | 2 +- protocol/utils/signer.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/utils/mint.js b/protocol/utils/mint.js index 21291deb8b..1dce1ca778 100644 --- a/protocol/utils/mint.js +++ b/protocol/utils/mint.js @@ -15,7 +15,7 @@ async function mintBeans(address, amount) { } async function mintEth(address) { - await hre.network.provider.send("hardhat_setBalance", [address, "0x3635C9ADC5DEA00000"]); + await hre.network.provider.send("hardhat_setBalance", [address, "0x21E19E0C9BAB2400000"]); } exports.mintEth = mintEth; diff --git a/protocol/utils/signer.js b/protocol/utils/signer.js index d6434dd96f..46d435f0d8 100644 --- a/protocol/utils/signer.js +++ b/protocol/utils/signer.js @@ -7,7 +7,7 @@ async function impersonateSigner(signerAddress, withEth = false) { }); if (withEth) { - await hre.network.provider.send("hardhat_setBalance", [signerAddress, "0x3635C9ADC5DEA00000"]); + await hre.network.provider.send("hardhat_setBalance", [signerAddress, "0x21E19E0C9BAB2400000"]); } return await ethers.getSigner(signerAddress) From 39bf809f93f1b66232da8fe845fe2e5e9b6289d3 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 6 Sep 2023 17:40:52 -0400 Subject: [PATCH 62/96] add migration test --- .../test/Bean3CrvToBeanEthMigration.test.js | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 protocol/test/Bean3CrvToBeanEthMigration.test.js diff --git a/protocol/test/Bean3CrvToBeanEthMigration.test.js b/protocol/test/Bean3CrvToBeanEthMigration.test.js new file mode 100644 index 0000000000..cb1393b638 --- /dev/null +++ b/protocol/test/Bean3CrvToBeanEthMigration.test.js @@ -0,0 +1,112 @@ +const { expect } = require('chai'); +const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot.js"); +const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK, BEAN_ETH_WELL, BCM, STABLE_FACTORY } = require('./utils/constants.js'); +const { setEthUsdcPrice, setEthUsdPrice } = require('../utils/oracle.js'); +const { to6, to18 } = require('./utils/helpers.js'); +const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); +const { getBeanstalk } = require('../utils/contracts.js'); +const { impersonateBeanstalkOwner } = require('../utils/signer.js'); +const { ethers } = require('hardhat'); +const { mintEth } = require('../utils/mint.js'); +let user,user2,owner; + +let underlyingBefore +let beanEthUnderlying +let snapshotId + + +describe('Bean:3Crv to Bean:Eth Migration', function () { + before(async function () { + + [user, user2] = await ethers.getSigners() + + try { + await network.provider.request({ + method: "hardhat_reset", + params: [ + { + forking: { + jsonRpcUrl: process.env.FORKING_RPC, + blockNumber: 18072000 //a random semi-recent block close to Grown Stalk Per Bdv pre-deployment + }, + }, + ], + }); + } catch(error) { + console.log('forking error in Silo V3: Grown Stalk Per Bdv:'); + console.log(error); + return + } + + owner = await impersonateBeanstalkOwner() + this.beanstalk = await getBeanstalk() + this.weth = await ethers.getContractAt('IWETH', WETH) + this.bean = await ethers.getContractAt('IBean', BEAN) + this.beanEth = await ethers.getContractAt('IWell', BEAN_ETH_WELL) + this.beanEthToken = await ethers.getContractAt('IERC20', BEAN_ETH_WELL) + this.unripeLp = await ethers.getContractAt('IERC20', UNRIPE_LP) + this.beanMetapool = await ethers.getContractAt('MockMeta3Curve', BEAN_3_CURVE) + underlyingBefore = await this.beanstalk.getTotalUnderlying(UNRIPE_LP); + + await bipMigrateUnripeBean3CrvToBeanEth(true, undefined, false) + }); + + beforeEach(async function () { + snapshotId = await takeSnapshot() + }); + + afterEach(async function () { + await revertToSnapshot(snapshotId) + }); + + describe('Initializes migration', async function () { + it('Changings underlying token', async function () { + expect(await this.beanstalk.getUnderlyingToken(UNRIPE_LP)).to.be.equal(BEAN_ETH_WELL) + }) + + it('Removes underlying balance', async function () { + expect(await this.beanstalk.getTotalUnderlying(UNRIPE_LP)).to.be.equal(0) + }) + + it('Sends underlying balance to BCM', async function () { + expect(await this.beanstalk.getExternalBalance(BCM, BEAN_3_CURVE)).to.be.equal(underlyingBefore) + }) + }) + + describe('Completes Migration', async function () { + beforeEach(async function () { + const balance = await this.beanMetapool.balanceOf(owner.address) + await this.beanMetapool.connect(owner).approve(BEANSTALK, balance) + await this.beanstalk.connect(owner).removeLiquidity( + BEAN_3_CURVE, + STABLE_FACTORY, + balance, + ['0', '0'], + '0', + '0' + ) + const balances = await this.beanEth.getReserves(); + const beans = await this.bean.balanceOf(owner.address) + const weth = beans.mul(balances[1]).div(balances[0]) + await this.weth.connect(owner).deposit({value: weth}) + + await this.weth.connect(owner).approve(BEAN_ETH_WELL, weth) + await this.bean.connect(owner).approve(BEAN_ETH_WELL, beans) + + await this.beanEth.connect(owner).addLiquidity( + [beans, weth], + 0, + owner.address, + ethers.constants.MaxUint256 + ); + beanEthUnderlying = await this.beanEthToken.balanceOf(owner.address) + await this.beanEthToken.connect(owner).approve(BEANSTALK, beanEthUnderlying) + await this.beanstalk.connect(owner).addMigratedUnderlying(UNRIPE_LP, beanEthUnderlying); + }) + + it("successfully adds underlying", async function () { + expect(await this.beanstalk.getTotalUnderlying(UNRIPE_LP)).to.be.equal(beanEthUnderlying) + expect(await this.beanstalk.getUnderlying(UNRIPE_LP, await this.unripeLp.totalSupply())).to.be.equal(beanEthUnderlying) + }) + }) +}) \ No newline at end of file From 20ea20d861955df61c6825defa8ea1073aa19e70 Mon Sep 17 00:00:00 2001 From: brendan Date: Sun, 10 Sep 2023 11:54:17 -0400 Subject: [PATCH 63/96] revert on 0 before migration completed --- .../contracts/beanstalk/barn/UnripeFacet.sol | 2 + .../test/Bean3CrvToBeanEthMigration.test.js | 42 ++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 74bca8ba5a..568d948895 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -60,6 +60,8 @@ contract UnripeFacet is ReentrancyGuard { underlyingAmount = _getPenalizedUnderlying(unripeToken, amount, unripeSupply); + require(underlyingAmount > 0, "Chop: no underlying"); + LibUnripe.decrementUnderlying(unripeToken, underlyingAmount); address underlyingToken = s.u[unripeToken].underlyingToken; diff --git a/protocol/test/Bean3CrvToBeanEthMigration.test.js b/protocol/test/Bean3CrvToBeanEthMigration.test.js index cb1393b638..7cf06735d1 100644 --- a/protocol/test/Bean3CrvToBeanEthMigration.test.js +++ b/protocol/test/Bean3CrvToBeanEthMigration.test.js @@ -1,14 +1,18 @@ const { expect } = require('chai'); const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot.js"); -const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK, BEAN_ETH_WELL, BCM, STABLE_FACTORY } = require('./utils/constants.js'); +const { BEAN, FERTILIZER, USDC, BEAN_3_CURVE, THREE_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK, BEAN_ETH_WELL, BCM, STABLE_FACTORY, PUBLIUS } = require('./utils/constants.js'); const { setEthUsdcPrice, setEthUsdPrice } = require('../utils/oracle.js'); const { to6, to18 } = require('./utils/helpers.js'); const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); const { getBeanstalk } = require('../utils/contracts.js'); -const { impersonateBeanstalkOwner } = require('../utils/signer.js'); +const { impersonateBeanstalkOwner, impersonateSigner } = require('../utils/signer.js'); const { ethers } = require('hardhat'); const { mintEth } = require('../utils/mint.js'); +const { ConvertEncoder } = require('./utils/encoder.js'); +const { setReserves } = require('../utils/well.js'); +const { toBN } = require('../utils/helpers.js'); let user,user2,owner; +let publius; let underlyingBefore let beanEthUnderlying @@ -38,8 +42,11 @@ describe('Bean:3Crv to Bean:Eth Migration', function () { return } + publius = await impersonateSigner(PUBLIUS, true) + owner = await impersonateBeanstalkOwner() this.beanstalk = await getBeanstalk() + this.well = await ethers.getContractAt('IWell', BEAN_ETH_WELL); this.weth = await ethers.getContractAt('IWETH', WETH) this.bean = await ethers.getContractAt('IBean', BEAN) this.beanEth = await ethers.getContractAt('IWell', BEAN_ETH_WELL) @@ -71,6 +78,37 @@ describe('Bean:3Crv to Bean:Eth Migration', function () { it('Sends underlying balance to BCM', async function () { expect(await this.beanstalk.getExternalBalance(BCM, BEAN_3_CURVE)).to.be.equal(underlyingBefore) }) + + describe('Interactions with Unripe fail', async function () { + it('chop fails', async function () { + await this.beanstalk.connect(publius).withdrawDeposit(UNRIPE_LP, '-56836', to6('1'), 1); + await expect(this.beanstalk.connect(publius).chop(UNRIPE_LP, to6('1'), 1, 0)).to.be.revertedWith("Chop: no underlying") + }) + + it('deposit fails', async function () { + await this.beanstalk.connect(publius).withdrawDeposit(UNRIPE_LP, '-56836', to6('1'), 1); + await expect(this.beanstalk.connect(publius).deposit(UNRIPE_LP, to6('1'), 1)).to.be.revertedWith('Silo: No Beans under Token.') + }) + + it('enrootDeposit fails', async function () { + await expect(this.beanstalk.connect(publius).enrootDeposit(UNRIPE_LP, '-56836', to6('1'))).to.be.revertedWith('SafeMath: subtraction overflow'); + }) + + it('enrootDeposits fails', async function () { + await expect(this.beanstalk.connect(publius).enrootDeposits(UNRIPE_LP, ['-56836'], [to6('1')])).to.be.revertedWith('SafeMath: subtraction overflow'); + }) + + it('convert Unripe Bean to LP fails', async function () { + console.log(await this.beanstalk.poolDeltaB(BEAN_ETH_WELL)) + await expect(this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['-16272'], [to6('200')])).to.be.revertedWith('SafeMath: subtraction overflow'); + }) + + it('convert Unripe LP to Bean fails', async function () { + const liquidityRemover = await impersonateSigner('0x7eaE23DD0f0d8289d38653BCE11b92F7807eFB64', true); + await this.well.connect(liquidityRemover).removeLiquidityOneToken(to18('29'), WETH, '0', liquidityRemover.address, ethers.constants.MaxUint256) + await expect(this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeLPToBeans(to6('200'), '0'), ['-56836'], [to6('200')])).to.be.revertedWith('SafeMath: division by zero'); + }) + }) }) describe('Completes Migration', async function () { From 4bb12a4dd323306911b3943f4102fac4ad4d56db Mon Sep 17 00:00:00 2001 From: brendan Date: Sun, 10 Sep 2023 11:54:34 -0400 Subject: [PATCH 64/96] update tests --- protocol/test/ConvertUnripe.test.js | 708 ++++++++++++++++------------ 1 file changed, 396 insertions(+), 312 deletions(-) diff --git a/protocol/test/ConvertUnripe.test.js b/protocol/test/ConvertUnripe.test.js index 4f6ad62a60..d77e2e8c74 100644 --- a/protocol/test/ConvertUnripe.test.js +++ b/protocol/test/ConvertUnripe.test.js @@ -1,10 +1,13 @@ const { expect } = require('chai'); const { deploy } = require('../scripts/deploy.js') const { EXTERNAL, INTERNAL, INTERNAL_EXTERNAL, INTERNAL_TOLERANT } = require('./utils/balances.js') -const { BEAN, THREE_CURVE, THREE_POOL, BEAN_3_CURVE, UNRIPE_BEAN, UNRIPE_LP } = require('./utils/constants') +const { BEAN, THREE_CURVE, THREE_POOL, BEAN_3_CURVE, UNRIPE_BEAN, UNRIPE_LP, WETH, BEANSTALK, BEAN_ETH_WELL } = require('./utils/constants') const { ConvertEncoder } = require('./utils/encoder.js') const { to6, to18, toBean, toStalk } = require('./utils/helpers.js') const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot"); +const { setEthUsdcPrice, setEthUsdPrice, setEthUsdtPrice, setOracleFailure, printPrices } = require('../utils/oracle.js'); +const { deployBasin } = require('../scripts/basin.js'); +const { toBN } = require('../utils/helpers.js'); const ZERO_BYTES = ethers.utils.formatBytes32String('0x0') let user, user2, owner; let userAddress, ownerAddress, user2Address; @@ -23,41 +26,52 @@ describe('Unripe Convert', function () { this.convert = await ethers.getContractAt('ConvertFacet', this.diamond.address); this.convertGet = await ethers.getContractAt('ConvertGettersFacet', this.diamond.address); this.bean = await ethers.getContractAt('MockToken', BEAN); - this.threePool = await ethers.getContractAt('Mock3Curve', THREE_POOL); - this.threeCurve = await ethers.getContractAt('MockToken', THREE_CURVE); - this.beanMetapool = await ethers.getContractAt('IMockCurvePool', BEAN_3_CURVE); + this.weth = await ethers.getContractAt('MockToken', WETH); - await this.threeCurve.mint(userAddress, to18('100000')); - await this.threePool.set_virtual_price(to18('1')); - await this.threeCurve.connect(user).approve(this.beanMetapool.address, to18('100000000000')); + this.well = await deployBasin(true, undefined, false, true) + this.wellToken = await ethers.getContractAt("IERC20", this.well.address) + await this.wellToken.connect(owner).approve(BEANSTALK, ethers.constants.MaxUint256) + await this.bean.connect(owner).approve(BEANSTALK, ethers.constants.MaxUint256) - await this.beanMetapool.connect(user).approve(this.threeCurve.address, to18('100000000000')); - await this.beanMetapool.connect(user).approve(this.silo.address, to18('100000000000')); + await setEthUsdPrice('999.998018') + await setEthUsdcPrice('1000') await this.season.siloSunrise(0); - await this.bean.mint(userAddress, toBean('1000000000')); - await this.bean.mint(user2Address, toBean('1000000000')); - await this.bean.connect(user).approve(this.beanMetapool.address, to18('100000000000')); - await this.bean.connect(user2).approve(this.beanMetapool.address, to18('100000000000')); - await this.bean.connect(user).approve(this.silo.address, '100000000000'); - await this.bean.connect(user2).approve(this.silo.address, '100000000000'); - await this.beanMetapool.connect(user).add_liquidity([toBean('1000'), to18('1000')], to18('2000')); - await this.beanMetapool.connect(user).transfer(ownerAddress, to18('1000')) + await this.bean.mint(userAddress, toBean('10000000000')); + await this.bean.mint(user2Address, toBean('10000000000')); + await this.weth.mint(userAddress, to18('1000000000')); + await this.weth.mint(user2Address, to18('1000000000')); + + await this.bean.connect(user).approve(this.well.address, ethers.constants.MaxUint256); + await this.bean.connect(user2).approve(this.well.address, ethers.constants.MaxUint256); + await this.bean.connect(owner).approve(this.well.address, ethers.constants.MaxUint256); + await this.weth.connect(user).approve(this.well.address, ethers.constants.MaxUint256); + await this.weth.connect(user2).approve(this.well.address, ethers.constants.MaxUint256); + await this.weth.connect(owner).approve(this.well.address, ethers.constants.MaxUint256); + await this.bean.connect(user).approve(this.silo.address, ethers.constants.MaxUint256); + await this.bean.connect(user2).approve(this.silo.address, ethers.constants.MaxUint256); + await this.wellToken.connect(user).approve(this.silo.address, ethers.constants.MaxUint256); + await this.wellToken.connect(user2).approve(this.silo.address, ethers.constants.MaxUint256); + + await this.well.connect(user).addLiquidity( + [toBean('10000'), to18('10')], + 0, + owner.address, + ethers.constants.MaxUint256 + ); this.unripe = await ethers.getContractAt('MockUnripeFacet', this.diamond.address) this.unripeBean = await ethers.getContractAt('MockToken', UNRIPE_BEAN) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) this.fertilizer = await ethers.getContractAt('MockFertilizerFacet', this.diamond.address) await this.unripeBean.mint(userAddress, to6('10000')) - await this.unripeLP.mint(userAddress, to6('9422.960000')) + await this.unripeLP.mint(userAddress, to6('31.622776')) await this.unripeBean.connect(user).approve(this.diamond.address, to18('100000000')) await this.unripeLP.connect(user).approve(this.diamond.address, to18('100000000')) await this.fertilizer.setFertilizerE(true, to6('10000')) await this.unripe.addUnripeToken(UNRIPE_BEAN, BEAN, ZERO_BYTES) - await this.unripe.addUnripeToken(UNRIPE_LP, BEAN_3_CURVE, ZERO_BYTES) + await this.unripe.addUnripeToken(UNRIPE_LP, BEAN_ETH_WELL, ZERO_BYTES) await this.bean.mint(ownerAddress, to6('5000')) - await this.bean.approve(this.diamond.address, to6('5000')) - await this.beanMetapool.approve(this.diamond.address, to18('10000')) await this.fertilizer.setPenaltyParams(to6('500'), '0') await this.unripe.connect(owner).addUnderlying( UNRIPE_BEAN, @@ -65,7 +79,7 @@ describe('Unripe Convert', function () { ) await this.unripe.connect(owner).addUnderlying( UNRIPE_LP, - to18('942.2960000') + to18('31.622776') // 31.622776601683793319 ) }); @@ -79,7 +93,12 @@ describe('Unripe Convert', function () { describe('calclates beans to peg', async function () { it('p > 1', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); + await this.well.connect(user).addLiquidity( + [toBean('0'), to18('0.2')], + '0', + user.address, + ethers.constants.MaxUint256 + ); expect(await this.convertGet.getMaxAmountIn(UNRIPE_BEAN, UNRIPE_LP)).to.be.equal(to6('2000')); }); @@ -88,15 +107,25 @@ describe('Unripe Convert', function () { }); it('p < 1', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); + await this.well.connect(user).addLiquidity( + [toBean('2000'), to18('0')], + '0', + user.address, + ethers.constants.MaxUint256 + ); expect(await this.convertGet.getMaxAmountIn(UNRIPE_BEAN, UNRIPE_LP)).to.be.equal('0'); }); }); describe('calclates lp to peg', async function () { it('p > 1', async function () { - await this.beanMetapool.connect(user2).add_liquidity([toBean('200'), to18('0')], to18('150')); - expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.within(to6('1990'), to6('2000')); + await this.well.connect(user).addLiquidity( + [toBean('0'), to18('0.2')], + '0', + user.address, + ethers.constants.MaxUint256 + ); + expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal('0'); }); it('p = 1', async function () { @@ -104,8 +133,13 @@ describe('Unripe Convert', function () { }); it('p < 1', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal('0'); + await this.well.connect(user).addLiquidity( + [toBean('2000'), to18('0')], + '0', + user.address, + ethers.constants.MaxUint256 + ); + expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal(to6('30.182395')); }); }) @@ -118,14 +152,15 @@ describe('Unripe Convert', function () { }); it('not enough LP', async function () { await this.silo.connect(user).deposit(this.unripeBean.address, to6('200'), EXTERNAL); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('20')], to18('15')); - await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), to6('200.1')), ['0'], [to6('200')])) - .to.be.revertedWith('Curve: Not enough LP'); + await this.well.connect(user).addLiquidity([toBean('0'), to18('0.02')], '0', user.address, ethers.constants.MaxUint256); + const amountOut = await this.well.getAddLiquidityOut([to6('200'), '0']) + await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), amountOut.add(toBN('1'))), ['0'], [to6('200')])) + .to.be.revertedWith('') }); it('p >= 1', async function () { await this.silo.connect(user).deposit(this.unripeBean.address, to6('200'), EXTERNAL); - await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), to6('190')), ['0'], ['1000'])) + await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['0'], ['1000'])) .to.be.revertedWith('Convert: P must be >= 1.'); }); }); @@ -136,307 +171,356 @@ describe('Unripe Convert', function () { this.season.deployStemsUpgrade(); }); beforeEach(async function () { - await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('1000'), to6('1000')), ['0'], [to6('2000')]) + await this.silo.connect(user).deposit( + this.unripeBean.address, to6('2000'), EXTERNAL + ); + await this.well.connect(user).addLiquidity( + [toBean('0'), to18('0.2')], + '0', + user.address, + ethers.constants.MaxUint256 + ); + this.result = await this.convert.connect(user).convert( + ConvertEncoder.convertUnripeBeansToLP(to6('1000'), '0'), ['0'], [to6('2000')] + ) }); it('properly updates total values', async function () { expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1000')); expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('1006344767'); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); - //expect(await this.silo.totalSeeds()).to.eq(toBean('600')); - expect(await this.silo.totalStalk()).to.eq(toStalk('200')); + expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('474652298'); + const bdv = await this.silo.bdv(this.unripeLP.address, '474652298') + expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(bdv); + expect(await this.silo.totalStalk()).to.eq(toStalk('100').add(bdv.mul(to6('0.01')))); }); - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(toBean('600')); - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200')); + it('properly updates user values -test', async function () { + const bdv = await this.silo.bdv(this.unripeLP.address, '474652298') + expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('100').add(bdv.mul(to6('0.01')))); }); it('properly updates user deposits', async function () { expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1000')); const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); - expect(deposit[0]).to.eq('1006344767'); - expect(deposit[1]).to.eq(toBean('100')); + expect(deposit[0]).to.eq('474652298'); + expect(deposit[1]).to.eq(await this.silo.bdv(this.unripeLP.address, '474652298')); }); it('emits events', async function () { await expect(this.result).to.emit(this.silo, 'RemoveDeposits') .withArgs(userAddress, this.unripeBean.address, [0], [to6('1000')], to6('1000'), [to6('100')]); await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 0, '1006344767', toBean('100')); - }); - }); - - describe('multiple crates', async function () { - beforeEach(async function () { - await this.season.teleportSunrise(10); - this.season.deployStemsUpgrade(); - await this.silo.connect(user).deposit(this.unripeBean.address, to6('1000'), EXTERNAL); - await this.season.siloSunrise(0); - await this.season.siloSunrise(0); - await this.season.siloSunrise(0); - await this.season.siloSunrise(0); //season 14 - - await this.silo.connect(user).deposit(this.unripeBean.address, to6('1000'), EXTERNAL); - - - const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('2500'), to6('1900')), [0, stemUnripeBean], [to6('1000'), to6('1000')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to18('0')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to18('0')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('2008324306'); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('200')); - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200.08')); - }); - - it('properly updates user values', async function () { - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200.08')); - }); - - it('properly updates user deposits', async function () { - const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); - - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(toBean('0')); - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, stemUnripeBean))[0]).to.eq(toBean('0')); - const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 4); - expect(deposit[0]).to.eq('2008324306'); - expect(deposit[1]).to.eq(toBean('200')); - }); - - it('emits events', async function () { - const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); - await expect(this.result).to.emit(this.silo, 'RemoveDeposits') - .withArgs(userAddress, this.unripeBean.address, [0, stemUnripeBean], [to6('1000'), to6('1000')], to6('2000'), [to6('100'), to6('100')]); - await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 4, '2008324306', toBean('200')); + .withArgs(userAddress, this.unripeLP.address, 0, '474652298', await this.silo.bdv(this.unripeLP.address, '474652298')); }); }); - //TODOSEEDS maybe write some tests that are not right on the zero index of grown stalk per bdv? - describe("bean more vested", async function () { - beforeEach(async function () { - await this.season.teleportSunrise(10); - this.season.deployStemsUpgrade(); - await this.unripe.connect(owner).addUnderlying( - UNRIPE_BEAN, - to6('1000') - ) - await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('500'), to6('500')), ['0'], [to6('500')]) - }) - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1500')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('300')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('503172383'); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); - //expect(await this.silo.totalSeeds()).to.eq(toBean('1000')); - expect(await this.silo.totalStalk()).to.eq(toStalk('400')); - }); - - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(toBean('1000')); - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('400')); - }); - - it('properly updates user deposits', async function () { - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1500')); - const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); - expect(deposit[0]).to.eq('503172383'); - expect(deposit[1]).to.eq(toBean('100')); - }); - - it('emits events', async function () { - await expect(this.result).to.emit(this.silo, 'RemoveDeposits') - .withArgs(userAddress, this.unripeBean.address, [0], [to6('500')], to6('500'), [to6('100')]); - await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 0, '503172383', toBean('100')); - }); - }) - - describe("lp more vested", async function () { - beforeEach(async function () { - await this.season.teleportSunrise(10); - this.season.deployStemsUpgrade(); - await this.unripe.connect(user).addUnderlyingWithRecap( - UNRIPE_LP, - to18('942.2960000') - ) - await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('200')], to18('150')); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('500'), to6('500')), ['0'], [to6('500')]) - }) - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1500')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('150')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('503761210'); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq('97342214'); - expect(await this.silo.totalStalk()).to.eq('2473422140000'); - }); - - it('properly updates user values', async function () { - expect(await this.silo.balanceOfStalk(userAddress)).to.eq('2473422140000'); - }); - - it('properly updates user deposits', async function () { - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1500')); - const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); - expect(deposit[0]).to.eq('503761210'); - expect(deposit[1]).to.eq('97342214'); - }); - - it('emits events', async function () { - await expect(this.result).to.emit(this.silo, 'RemoveDeposits') - .withArgs(userAddress, this.unripeBean.address, [0], [to6('500')], to6('500'), [to6('50')]); - await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 0, '503761210', '97342214'); - }); - }) +// describe('multiple crates', async function () { +// beforeEach(async function () { +// await this.season.teleportSunrise(10); +// this.season.deployStemsUpgrade(); +// await this.silo.connect(user).deposit(this.unripeBean.address, to6('1000'), EXTERNAL); +// await this.season.siloSunrise(0); +// await this.season.siloSunrise(0); +// await this.season.siloSunrise(0); +// await this.season.siloSunrise(0); //season 14 + +// await this.silo.connect(user).deposit(this.unripeBean.address, to6('1000'), EXTERNAL); + + +// const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); +// await this.well.connect(user).addLiquidity( +// [toBean('0'), to18('0.2')], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('2500'), '0'), [0, stemUnripeBean], [to6('1000'), to6('1000')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to18('0')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to18('0')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('2008324306'); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('200')); +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200.08')); +// }); + +// it('properly updates user values', async function () { +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('200.08')); +// }); + +// it('properly updates user deposits', async function () { +// const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); + +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(toBean('0')); +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, stemUnripeBean))[0]).to.eq(toBean('0')); +// const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 4); +// expect(deposit[0]).to.eq('2008324306'); +// expect(deposit[1]).to.eq(toBean('200')); +// }); + +// it('emits events', async function () { +// const stemUnripeBean = await this.silo.seasonToStem(this.unripeBean.address, '14'); +// await expect(this.result).to.emit(this.silo, 'RemoveDeposits') +// .withArgs(userAddress, this.unripeBean.address, [0, stemUnripeBean], [to6('1000'), to6('1000')], to6('2000'), [to6('100'), to6('100')]); +// await expect(this.result).to.emit(this.silo, 'AddDeposit') +// .withArgs(userAddress, this.unripeLP.address, 4, '2008324306', toBean('200')); +// }); +// }); +// //TODOSEEDS maybe write some tests that are not right on the zero index of grown stalk per bdv? +// describe("bean more vested", async function () { +// beforeEach(async function () { +// await this.season.teleportSunrise(10); +// this.season.deployStemsUpgrade(); +// await this.unripe.connect(owner).addUnderlying( +// UNRIPE_BEAN, +// to6('1000') +// ) +// await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); +// await this.well.connect(user).addLiquidity( +// [toBean('0'), to18('0.2')], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('500'), '0'), ['0'], [to6('500')]) +// }) + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1500')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('300')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('503172383'); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); +// //expect(await this.silo.totalSeeds()).to.eq(toBean('1000')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('400')); +// }); + +// it('properly updates user values', async function () { +// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(toBean('1000')); +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('400')); +// }); + +// it('properly updates user deposits', async function () { +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1500')); +// const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); +// expect(deposit[0]).to.eq('503172383'); +// expect(deposit[1]).to.eq(toBean('100')); +// }); + +// it('emits events', async function () { +// await expect(this.result).to.emit(this.silo, 'RemoveDeposits') +// .withArgs(userAddress, this.unripeBean.address, [0], [to6('500')], to6('500'), [to6('100')]); +// await expect(this.result).to.emit(this.silo, 'AddDeposit') +// .withArgs(userAddress, this.unripeLP.address, 0, '503172383', toBean('100')); +// }); +// }) + +// describe("lp more vested", async function () { +// beforeEach(async function () { +// await this.season.teleportSunrise(10); +// this.season.deployStemsUpgrade(); +// await this.unripe.connect(user).addUnderlyingWithRecap( +// UNRIPE_LP, +// to18('942.2960000') +// ) +// await this.silo.connect(user).deposit(this.unripeBean.address, to6('2000'), EXTERNAL); +// await this.well.connect(user).addLiquidity( +// [toBean('0'), to18('0.2')], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeBeansToLP(to6('500'), '0'), ['0'], [to6('500')]) +// }) + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1500')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('150')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('503761210'); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq('97342214'); +// expect(await this.silo.totalStalk()).to.eq('2473422140000'); +// }); + +// it('properly updates user values', async function () { +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq('2473422140000'); +// }); + +// it('properly updates user deposits', async function () { +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1500')); +// const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); +// expect(deposit[0]).to.eq('503761210'); +// expect(deposit[1]).to.eq('97342214'); +// }); + +// it('emits events', async function () { +// await expect(this.result).to.emit(this.silo, 'RemoveDeposits') +// .withArgs(userAddress, this.unripeBean.address, [0], [to6('500')], to6('500'), [to6('50')]); +// await expect(this.result).to.emit(this.silo, 'AddDeposit') +// .withArgs(userAddress, this.unripeLP.address, 0, '503761210', '97342214'); +// }); +// }) }); - describe('convert lp to beans', async function () { - beforeEach(async function () { - await this.season.teleportSunrise(10); - this.season.deployStemsUpgrade(); - }); - - describe('revert', async function () { - it('not enough Beans', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) - .to.be.revertedWith('Curve: Insufficient Output'); - }); - - it('p >= 1', async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('0'), to18('1')], to18('0.5')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) - .to.be.revertedWith('Convert: P must be < 1.'); - }); - }); - - describe('below max', function () { - beforeEach(async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990')), ['0'], [to6('1000')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); - //expect(await this.silo.totalSeeds()).to.eq(to6('201.236334')); - expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); - }); - - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('201.236334')); - expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); - }); - }); - - //these tests use the new 2 seeds per bdv instead of previous 4 (note in the beforeEach above that deployStemsUpgrade is called) - describe('multiple crates', function () { - beforeEach(async function () { - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('500'), EXTERNAL); - - await this.season.siloSunrise(0); - await this.season.siloSunrise(0); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('500'), EXTERNAL); - - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990'), this.unripeLP.address), ['0', '4'], [to6('500'), to6('500')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); - expect(await this.silo.totalStalk()).to.eq(toStalk('100.6282288167')); - //same as normal curve convert tests, old value was 100.6382906334 but now with rounding it's a bit different - }); - - it('properly updates user values', async function () { - expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('100.6282288167')); - }); - - it('properly updates user deposits', async function () { - expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 3))[0]).to.eq(to6('1006.18167')); - const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 2); - expect(deposit[0]).to.eq(to6('0')); - expect(deposit[1]).to.eq(toBean('0')); - }); - - it('emits events', async function () { - await expect(this.result).to.emit(this.silo, 'RemoveDeposits') - .withArgs(userAddress, this.unripeLP.address, [0, 4], [to6('500'), to6('500')], to6('1000'), [to6('50'), to6('50')]); - await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeBean.address, 3, to6('1006.18167'), to6('100.618167')); - }); - }); - - describe('bean over vested', function () { - beforeEach(async function () { - await this.unripe.connect(owner).addUnderlying( - UNRIPE_BEAN, - to6('1000') - ) - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('1000')), ['0'], [to6('1000')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('192.037852')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); - //expect(await this.silo.totalSeeds()).to.eq(to6('384.075704')); - expect(await this.silo.totalStalk()).to.eq(toStalk('192.037852')); - }); - - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('384.075704')); - expect(await this.silo.totalStalk()).to.eq(toStalk('192.037852')); - }); - }); - - describe('bean under vested', function () { - beforeEach(async function () { - await this.unripe.connect(user).addUnderlyingWithRecap( - UNRIPE_LP, - to18('942.2960000') - ) - await this.beanMetapool.connect(user).add_liquidity([toBean('200'), to18('0')], to18('150')); - await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); - this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('500'), to6('500')), ['0'], [to6('1000')]) - }); - - it('properly updates total values', async function () { - expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('503.090835')); - expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('500')); - expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); - //expect(await this.silo.totalSeeds()).to.eq(to6('600')); - expect(await this.silo.totalStalk()).to.eq(toStalk('200')); - }); - - it('properly updates user values', async function () { - //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('600')); - expect(await this.silo.totalStalk()).to.eq(toStalk('200')); - }); - }); - }); +// describe('convert lp to beans', async function () { +// beforeEach(async function () { +// await this.season.teleportSunrise(10); +// this.season.deployStemsUpgrade(); +// }); + +// describe('revert', async function () { +// it('not enough Beans', async function () { +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) +// .to.be.revertedWith('Curve: Insufficient Output'); +// }); + +// it('p >= 1', async function () { +// await this.well.connect(user).addLiquidity([toBean('0'), to18('1')], to18('0.5')); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) +// .to.be.revertedWith('Convert: P must be < 1.'); +// }); +// }); + +// describe('below max', function () { +// beforeEach(async function () { +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990')), ['0'], [to6('1000')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); +// //expect(await this.silo.totalSeeds()).to.eq(to6('201.236334')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); +// }); + +// it('properly updates user values', async function () { +// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('201.236334')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); +// }); +// }); + +// //these tests use the new 2 seeds per bdv instead of previous 4 (note in the beforeEach above that deployStemsUpgrade is called) +// describe('multiple crates', function () { +// beforeEach(async function () { +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('500'), EXTERNAL); + +// await this.season.siloSunrise(0); +// await this.season.siloSunrise(0); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('500'), EXTERNAL); + +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990'), this.unripeLP.address), ['0', '4'], [to6('500'), to6('500')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('100.6282288167')); +// //same as normal curve convert tests, old value was 100.6382906334 but now with rounding it's a bit different +// }); + +// it('properly updates user values', async function () { +// expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('100.6282288167')); +// }); + +// it('properly updates user deposits', async function () { +// expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 3))[0]).to.eq(to6('1006.18167')); +// const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 2); +// expect(deposit[0]).to.eq(to6('0')); +// expect(deposit[1]).to.eq(toBean('0')); +// }); + +// it('emits events', async function () { +// await expect(this.result).to.emit(this.silo, 'RemoveDeposits') +// .withArgs(userAddress, this.unripeLP.address, [0, 4], [to6('500'), to6('500')], to6('1000'), [to6('50'), to6('50')]); +// await expect(this.result).to.emit(this.silo, 'AddDeposit') +// .withArgs(userAddress, this.unripeBean.address, 3, to6('1006.18167'), to6('100.618167')); +// }); +// }); + +// describe('bean over vested', function () { +// beforeEach(async function () { +// await this.unripe.connect(owner).addUnderlying( +// UNRIPE_BEAN, +// to6('1000') +// ) +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('1000')), ['0'], [to6('1000')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('192.037852')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); +// //expect(await this.silo.totalSeeds()).to.eq(to6('384.075704')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('192.037852')); +// }); + +// it('properly updates user values', async function () { +// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('384.075704')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('192.037852')); +// }); +// }); + +// describe('bean under vested', function () { +// beforeEach(async function () { +// await this.unripe.connect(user).addUnderlyingWithRecap( +// UNRIPE_LP, +// to18('942.2960000') +// ) +// await this.well.connect(user).addLiquidity( +// [toBean('200'), '0'], +// '0', +// user.address, +// ethers.constants.MaxUint256 +// ); +// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); +// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('500'), to6('500')), ['0'], [to6('1000')]) +// }); + +// it('properly updates total values', async function () { +// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('503.090835')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100')); +// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('500')); +// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('100')); +// //expect(await this.silo.totalSeeds()).to.eq(to6('600')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('200')); +// }); + +// it('properly updates user values', async function () { +// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('600')); +// expect(await this.silo.totalStalk()).to.eq(toStalk('200')); +// }); +// }); +// }); }); From 71901cb67e265e6fccfe0976cde45f4555277c23 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 13:18:37 -0400 Subject: [PATCH 65/96] Bean eth migration script --- protocol/scripts/beanEthMigration.js | 90 ++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 protocol/scripts/beanEthMigration.js diff --git a/protocol/scripts/beanEthMigration.js b/protocol/scripts/beanEthMigration.js new file mode 100644 index 0000000000..d8e483aa7e --- /dev/null +++ b/protocol/scripts/beanEthMigration.js @@ -0,0 +1,90 @@ +const { BEAN_ETH_WELL, BEAN_3_CURVE, STABLE_FACTORY, USDT, TRI_CRYPTO_POOL, CURVE_REGISTRY, WETH, BEAN, BEANSTALK, THREE_CURVE, THREE_POOL, CRYPTO_REGISTRY, UNRIPE_LP } = require("../test/utils/constants"); +const { toX } = require("../test/utils/helpers"); +const { getBeanstalk, impersonateBeanstalkOwner } = require("../utils"); + + +async function completeBeanEthMigration() { + const owner = await impersonateBeanstalkOwner() + const beanstalk = await getBeanstalk() + const well = await ethers.getContractAt('IWell', BEAN_ETH_WELL) + const bean3CrvToken = await ethers.getContractAt('IERC20', BEAN_3_CURVE); + const threeCrvToken = await ethers.getContractAt('IERC20', THREE_CURVE); + const bean = await ethers.getContractAt('IERC20', BEAN); + const weth = await ethers.getContractAt('IWETH', WETH); + const beanEthToken = await ethers.getContractAt('IERC20', BEAN_ETH_WELL); + const usdt = await ethers.getContractAt('IERC20', USDT); + let balance = await beanstalk.getExternalBalance(owner.address, BEAN_3_CURVE) + console.log(`Bean 3 Crv Balance: ${balance}`) + await bean3CrvToken.connect(owner).approve(BEANSTALK, balance); + await beanstalk.connect(owner).removeLiquidity( + BEAN_3_CURVE, + STABLE_FACTORY, + balance, + ['0', '0'], + '0', + '0' + ) + + + balance = await beanstalk.getExternalBalance(owner.address, THREE_CURVE) + console.log(`3 Crv Balance: ${balance}`) + await threeCrvToken.connect(owner).approve(BEANSTALK, balance); + await beanstalk.connect(owner).removeLiquidityOneToken( + THREE_POOL, + CURVE_REGISTRY, + USDT, + balance, + '0', + '0', + '0' + ) + balance = await beanstalk.getExternalBalance(owner.address, USDT) + console.log(`USDT: ${balance}`) + await usdt.connect(owner).approve(BEANSTALK, balance); + await beanstalk.connect(owner).exchange( + TRI_CRYPTO_POOL, + CRYPTO_REGISTRY, + USDT, + WETH, + balance, + '0', + '0', + '0' + ) + + let balances = await well.getReserves(); + console.log(`Well Bean Balance Before: ${balances[0]}`); + console.log(`Well WETH Balance Before: ${balances[1]}`); + console.log(`Well Price b4: ${balances[0].mul(toX('1', 12)).div(balances[1])}`) + + const beanBalance = await beanstalk.getExternalBalance(owner.address, BEAN) + const wethBalance = await beanstalk.getExternalBalance(owner.address, WETH) + + const ethToAdd = balances[1].div(balances[0]).mul(beanBalance) + await weth.deposit({value: ethToAdd.sub(wethBalance)}) + + console.log(`Bean Balance: ${beanBalance}`); + console.log(`WETH Balance: ${balances[1]}`); + + await bean.connect(owner).approve(BEAN_ETH_WELL, balances[0]); + await weth.connect(owner).approve(BEAN_ETH_WELL, balances[1]); + await well.connect(owner).addLiquidity( + [beanBalance , ethToAdd], + '0', + owner.address, + ethers.constants.MaxUint256 + ) + + balance = await beanstalk.getExternalBalance(owner.address, BEAN_ETH_WELL) + console.log(`Well LP Balance: ${balance}`) + await beanEthToken.connect(owner).approve(BEANSTALK, balance); + await beanstalk.connect(owner).addMigratedUnderlying(UNRIPE_LP, balance); + console.log(`Unripe LP Underlying Balance: ${await beanstalk.getTotalUnderlying(UNRIPE_LP)}`) + + balances = await well.getReserves(); + console.log(`Well Bean Balance: ${balances[0]}`); + console.log(`Well WETH Balance: ${balances[1]}`); + console.log(`Price after: ${balances[0].mul(toX('1', 12)).div(balances[1])}`) +} + +exports.completeBeanEthMigration = completeBeanEthMigration; \ No newline at end of file From 27882370c2afc6d3a85f43494098a8a3a9f8fc43 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 14:49:28 -0400 Subject: [PATCH 66/96] all tests working --- protocol/scripts/beanEthMigration.js | 72 ++++++------------- .../test/Bean3CrvToBeanEthMigration.test.js | 3 +- protocol/test/Fertilizer.test.js | 2 - protocol/test/Stem.test.js | 50 ++++++++----- protocol/test/Sun.test.js | 29 +++++--- 5 files changed, 72 insertions(+), 84 deletions(-) diff --git a/protocol/scripts/beanEthMigration.js b/protocol/scripts/beanEthMigration.js index d8e483aa7e..b75dd3bdf5 100644 --- a/protocol/scripts/beanEthMigration.js +++ b/protocol/scripts/beanEthMigration.js @@ -1,10 +1,13 @@ const { BEAN_ETH_WELL, BEAN_3_CURVE, STABLE_FACTORY, USDT, TRI_CRYPTO_POOL, CURVE_REGISTRY, WETH, BEAN, BEANSTALK, THREE_CURVE, THREE_POOL, CRYPTO_REGISTRY, UNRIPE_LP } = require("../test/utils/constants"); const { toX } = require("../test/utils/helpers"); const { getBeanstalk, impersonateBeanstalkOwner } = require("../utils"); +const { bipMigrateUnripeBean3CrvToBeanEth } = require("./bips"); - -async function completeBeanEthMigration() { +async function finishBeanEthMigration(verbose = false) { const owner = await impersonateBeanstalkOwner() + + await hre.network.provider.send("hardhat_setBalance", [owner.address, "0x152D02C7E14AF6800000"]); + const beanstalk = await getBeanstalk() const well = await ethers.getContractAt('IWell', BEAN_ETH_WELL) const bean3CrvToken = await ethers.getContractAt('IERC20', BEAN_3_CURVE); @@ -14,7 +17,7 @@ async function completeBeanEthMigration() { const beanEthToken = await ethers.getContractAt('IERC20', BEAN_ETH_WELL); const usdt = await ethers.getContractAt('IERC20', USDT); let balance = await beanstalk.getExternalBalance(owner.address, BEAN_3_CURVE) - console.log(`Bean 3 Crv Balance: ${balance}`) + if (verbose) console.log(`Bean 3 Crv Balance: ${balance}`) await bean3CrvToken.connect(owner).approve(BEANSTALK, balance); await beanstalk.connect(owner).removeLiquidity( BEAN_3_CURVE, @@ -25,66 +28,33 @@ async function completeBeanEthMigration() { '0' ) - - balance = await beanstalk.getExternalBalance(owner.address, THREE_CURVE) - console.log(`3 Crv Balance: ${balance}`) - await threeCrvToken.connect(owner).approve(BEANSTALK, balance); - await beanstalk.connect(owner).removeLiquidityOneToken( - THREE_POOL, - CURVE_REGISTRY, - USDT, - balance, - '0', - '0', - '0' - ) - balance = await beanstalk.getExternalBalance(owner.address, USDT) - console.log(`USDT: ${balance}`) - await usdt.connect(owner).approve(BEANSTALK, balance); - await beanstalk.connect(owner).exchange( - TRI_CRYPTO_POOL, - CRYPTO_REGISTRY, - USDT, - WETH, - balance, - '0', - '0', - '0' - ) - let balances = await well.getReserves(); - console.log(`Well Bean Balance Before: ${balances[0]}`); - console.log(`Well WETH Balance Before: ${balances[1]}`); - console.log(`Well Price b4: ${balances[0].mul(toX('1', 12)).div(balances[1])}`) - const beanBalance = await beanstalk.getExternalBalance(owner.address, BEAN) - const wethBalance = await beanstalk.getExternalBalance(owner.address, WETH) - - const ethToAdd = balances[1].div(balances[0]).mul(beanBalance) - await weth.deposit({value: ethToAdd.sub(wethBalance)}) - - console.log(`Bean Balance: ${beanBalance}`); - console.log(`WETH Balance: ${balances[1]}`); - - await bean.connect(owner).approve(BEAN_ETH_WELL, balances[0]); - await weth.connect(owner).approve(BEAN_ETH_WELL, balances[1]); + const wethBalance = balances[1].div(balances[0]).mul(beanBalance) + await weth.connect(owner).deposit({value: wethBalance}) + await bean.connect(owner).approve(BEAN_ETH_WELL, beanBalance); + await weth.connect(owner).approve(BEAN_ETH_WELL, wethBalance); await well.connect(owner).addLiquidity( - [beanBalance , ethToAdd], + [beanBalance , wethBalance], '0', owner.address, ethers.constants.MaxUint256 ) balance = await beanstalk.getExternalBalance(owner.address, BEAN_ETH_WELL) - console.log(`Well LP Balance: ${balance}`) await beanEthToken.connect(owner).approve(BEANSTALK, balance); await beanstalk.connect(owner).addMigratedUnderlying(UNRIPE_LP, balance); - console.log(`Unripe LP Underlying Balance: ${await beanstalk.getTotalUnderlying(UNRIPE_LP)}`) + if (verbose) console.log(`Unripe LP Underlying Balance: ${await beanstalk.getTotalUnderlying(UNRIPE_LP)}`) balances = await well.getReserves(); - console.log(`Well Bean Balance: ${balances[0]}`); - console.log(`Well WETH Balance: ${balances[1]}`); - console.log(`Price after: ${balances[0].mul(toX('1', 12)).div(balances[1])}`) + if (verbose) console.log(`Well Bean Balance: ${balances[0]}`); + if (verbose) console.log(`Well WETH Balance: ${balances[1]}`); +} + +async function migrateBean3CrvToBeanEth() { + await bipMigrateUnripeBean3CrvToBeanEth() + await finishBeanEthMigration() } -exports.completeBeanEthMigration = completeBeanEthMigration; \ No newline at end of file +exports.finishBeanEthMigration = finishBeanEthMigration; +exports.migrateBean3CrvToBeanEth = migrateBean3CrvToBeanEth; \ No newline at end of file diff --git a/protocol/test/Bean3CrvToBeanEthMigration.test.js b/protocol/test/Bean3CrvToBeanEthMigration.test.js index 7cf06735d1..5970679f8f 100644 --- a/protocol/test/Bean3CrvToBeanEthMigration.test.js +++ b/protocol/test/Bean3CrvToBeanEthMigration.test.js @@ -99,8 +99,7 @@ describe('Bean:3Crv to Bean:Eth Migration', function () { }) it('convert Unripe Bean to LP fails', async function () { - console.log(await this.beanstalk.poolDeltaB(BEAN_ETH_WELL)) - await expect(this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['-16272'], [to6('200')])).to.be.revertedWith('SafeMath: subtraction overflow'); + await expect(this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['-16272'], [to6('200')])).to.be.revertedWith('SafeMath: division by zero'); }) it('convert Unripe LP to Bean fails', async function () { diff --git a/protocol/test/Fertilizer.test.js b/protocol/test/Fertilizer.test.js index adab06a69c..a7a1df7540 100644 --- a/protocol/test/Fertilizer.test.js +++ b/protocol/test/Fertilizer.test.js @@ -43,8 +43,6 @@ describe('Fertilize', function () { this.token = await ethers.getContractAt('TokenFacet', this.diamond.address) this.usdc = await ethers.getContractAt('IBean', USDC) this.bean = await ethers.getContractAt('IBean', BEAN) - this.well = await ethers.getContractAt('IBean', BEAN_3_CURVE) - this.weth = await ethers.getContractAt('IBean', THREE_CURVE) this.weth = await ethers.getContractAt('IBean', WETH) this.unripeBean = await ethers.getContractAt('MockToken', UNRIPE_BEAN) diff --git a/protocol/test/Stem.test.js b/protocol/test/Stem.test.js index 381975a3c7..53789aead7 100644 --- a/protocol/test/Stem.test.js +++ b/protocol/test/Stem.test.js @@ -10,6 +10,12 @@ const { upgradeWithNewFacets } = require("../scripts/diamond"); const { time, mineUpTo, mine } = require("@nomicfoundation/hardhat-network-helpers"); const { ConvertEncoder } = require('./utils/encoder.js'); const { BigNumber } = require('ethers'); +const { deployBasin } = require('../scripts/basin.js'); +const { setReserves } = require('../utils/well.js'); +const { setEthUsdPrice, setEthUsdcPrice } = require('../utils/oracle.js'); +const { impersonateEthUsdChainlinkAggregator, impersonateEthUsdcUniswap, impersonateBean, impersonateWeth } = require('../scripts/impersonate.js'); +const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); +const { finishBeanEthMigration } = require('../scripts/beanEthMigration.js'); require('dotenv').config(); let user,user2,owner; @@ -37,7 +43,6 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { } const signer = await impersonateBeanstalkOwner() - await mintEth(signer.address); await upgradeWithNewFacets({ diamondAddress: BEANSTALK, facetNames: ['EnrootFacet', 'ConvertFacet', 'WhitelistFacet', 'MockSiloFacet', 'MockSeasonFacet', 'MigrationFacet'], @@ -64,6 +69,21 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { this.unripeBean = await ethers.getContractAt('MockToken', UNRIPE_BEAN) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) this.threeCurve = await ethers.getContractAt('MockToken', THREE_CURVE); + this.well = await deployBasin(true, undefined, false, true) + + await impersonateEthUsdChainlinkAggregator() + await impersonateEthUsdcUniswap() + + await setEthUsdPrice('999.998018') + await setEthUsdcPrice('1000') + + await impersonateBean() + await impersonateWeth() + + await setReserves(owner, this.well, [to6('100001'), to18('100')]) + + await bipMigrateUnripeBean3CrvToBeanEth(true, undefined, false) + await finishBeanEthMigration() }); @@ -256,8 +276,7 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { amounts.push(newSeason); } - const depositorSigner = await impersonateSigner(depositorAddress); - await mintEth(depositorAddress); + const depositorSigner = await impersonateSigner(depositorAddress, true); await this.migrate.connect(depositorSigner).mowAndMigrate(depositorAddress, tokens, seasons, amounts, 0, 0, []); await this.silo.mow(depositorAddress, this.beanMetapool.address) }); @@ -461,8 +480,7 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { const depositorAddress = '0x5e68bb3de6133baee55eeb6552704df2ec09a824'; const token = '0x1bea3ccd22f4ebd3d37d731ba31eeca95713716d'; const stem = await this.silo.seasonToStem(token, 6061); - await mintEth(depositorAddress); - const depositorSigner = await impersonateSigner(depositorAddress); + const depositorSigner = await impersonateSigner(depositorAddress, true); await this.silo.connect(depositorSigner); await expect(this.convert.connect(depositorSigner).convert(ConvertEncoder.convertCurveLPToBeans(to6('7863'), to6('0'), this.beanMetapool.address), [stem], [to6('7863')])).to.be.revertedWith('Silo: Migration needed') }); @@ -475,13 +493,12 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { const depositorAddress = '0x10bf1dcb5ab7860bab1c3320163c6dddf8dcc0e4'; const token = '0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab'; const stem = await this.silo.seasonToStem(token, 7563); - await mintEth(depositorAddress); const threecrvHolder = '0xe74b28c2eAe8679e3cCc3a94d5d0dE83CCB84705' const threecrvSigner = await impersonateSigner(threecrvHolder); await this.threeCurve.connect(threecrvSigner).approve(this.beanMetapool.address, to18('100000000000')); await this.beanMetapool.connect(threecrvSigner).add_liquidity([to6('0'), to18('10000000')], to18('150')); - const depositorSigner = await impersonateSigner(depositorAddress); + const depositorSigner = await impersonateSigner(depositorAddress, true); await this.silo.connect(depositorSigner); await expect(this.convert.connect(depositorSigner).convert(ConvertEncoder.convertBeansToCurveLP(to6('345000'), to6('340000'), this.beanMetapool.address), [stem], [to6('345000')])).to.be.revertedWith('Silo: Migration needed') }); @@ -490,29 +507,24 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { const depositorAddress = '0x5e68bb3de6133baee55eeb6552704df2ec09a824'; const token = '0x1bea3ccd22f4ebd3d37d731ba31eeca95713716d'; const stem = await this.silo.seasonToStem(token, 6061); - await mintEth(depositorAddress); - - const depositorSigner = await impersonateSigner(depositorAddress); + const depositorSigner = await impersonateSigner(depositorAddress, true); await this.silo.connect(depositorSigner); await expect( this.convert.connect(depositorSigner).convert( - ConvertEncoder.convertUnripeLPToBeans(to6('7863'), to6('7500')), [stem], [to6('7863')])) + ConvertEncoder.convertUnripeLPToBeans(to6('7863'), '0'), [stem], [to6('7863')])) .to.be.revertedWith('Silo: Migration needed') }); it('attempt to convert unripe bean before migrating', async function () { + const reserves = await this.well.getReserves(); + await setReserves(owner, this.well, [reserves[0], reserves[1].add(to18('50'))]) + const urBean = '0x1bea0050e63e05fbb5d8ba2f10cf5800b6224449'; const stem = await this.silo.seasonToStem(urBean, 6074); const depositorAddress = '0x10bf1dcb5ab7860bab1c3320163c6dddf8dcc0e4'; - await mintEth(depositorAddress); - const depositorSigner = await impersonateSigner(depositorAddress); - - const threecrvHolder = '0xe74b28c2eAe8679e3cCc3a94d5d0dE83CCB84705' - const threecrvSigner = await impersonateSigner(threecrvHolder); - await this.threeCurve.connect(threecrvSigner).approve(this.beanMetapool.address, to18('100000000000')); - await this.beanMetapool.connect(threecrvSigner).add_liquidity([to6('0'), to18('10000000')], to18('150')); - await expect(this.convert.connect(depositorSigner).convert(ConvertEncoder.convertUnripeBeansToLP(to6('345000'), to6('340000')), [stem], [to6('345000')])).to.be.revertedWith('Silo: Migration needed') + const depositorSigner = await impersonateSigner(depositorAddress, true); + await expect(this.convert.connect(depositorSigner).convert(ConvertEncoder.convertUnripeBeansToLP(to6('345000'), to6('0')), [stem], [to6('345000')])).to.be.revertedWith('Silo: Migration needed') }); }); }); \ No newline at end of file diff --git a/protocol/test/Sun.test.js b/protocol/test/Sun.test.js index 3530728364..a03b7ba0ce 100644 --- a/protocol/test/Sun.test.js +++ b/protocol/test/Sun.test.js @@ -2,10 +2,12 @@ const { expect } = require('chai') const { deploy } = require('../scripts/deploy.js') const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot") const { to6, toStalk, toBean, to18 } = require('./utils/helpers.js'); -const { USDC, UNRIPE_LP, BEAN,ETH_USDC_UNISWAP_V3, BASE_FEE_CONTRACT, THREE_CURVE, THREE_POOL, BEAN_3_CURVE } = require('./utils/constants.js'); +const { USDC, UNRIPE_LP, BEAN,ETH_USDC_UNISWAP_V3, BASE_FEE_CONTRACT, THREE_CURVE, THREE_POOL, BEAN_3_CURVE, WETH } = require('./utils/constants.js'); const { EXTERNAL, INTERNAL } = require('./utils/balances.js'); const { ethers } = require('hardhat'); -const { deployMockWell } = require('../utils/well.js'); +const { deployMockWell, setReserves } = require('../utils/well.js'); +const { setEthUsdPrice, setEthUsdcPrice } = require('../utils/oracle.js'); +const { deployBasin } = require('../scripts/basin.js'); let user, user2, owner; let userAddress, ownerAddress, user2Address; @@ -23,6 +25,7 @@ describe('Sun', function () { this.silo = await ethers.getContractAt('MockSiloFacet', this.diamond.address) this.field = await ethers.getContractAt('MockFieldFacet', this.diamond.address) this.usdc = await ethers.getContractAt('MockToken', USDC); + this.weth = await ethers.getContractAt('MockToken', WETH); // These are needed for sunrise incentive test this.basefee = await ethers.getContractAt('MockBlockBasefee', BASE_FEE_CONTRACT); @@ -41,11 +44,16 @@ describe('Sun', function () { await this.usdc.mint(owner.address, to6('10000')) await this.bean.mint(owner.address, to6('10000')) + await this.weth.mint(owner.address, to18('10000')) await this.usdc.connect(owner).approve(this.diamond.address, to6('10000')) + await this.weth.connect(owner).approve(this.diamond.address, to18('10000')) this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) await this.unripeLP.mint(owner.address, to6('10000')); - [this.well, this.wellFunction, this.pump] = await deployMockWell() + await setEthUsdPrice('999.998018'); + await setEthUsdcPrice('1000'); + + this.well = await deployBasin(true, undefined, false, true) await this.season.siloSunrise(0) }) @@ -133,7 +141,7 @@ describe('Sun', function () { it("all harvestable and all fertilizable", async function () { await this.field.incrementTotalPodsE(to6('50')); - await this.fertilizer.connect(owner).addFertilizerOwner('6274', '20', '0'); + await this.fertilizer.connect(owner).addFertilizerOwner('6274', to18('0.02'), '0'); this.result = await this.season.sunSunrise(to6('200'), 8); expect(await this.field.totalSoil()).to.be.equal('49504950'); @@ -155,7 +163,7 @@ describe('Sun', function () { it("all harvestable, some fertilizable", async function () { await this.field.incrementTotalPodsE('500'); - await this.fertilizer.connect(owner).addFertilizerOwner('0', '1', '0'); + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.001'), '0'); this.result = await this.season.sunSunrise('2000', 8); await expect(this.result).to.emit(this.season, 'Soil').withArgs(3, '495'); expect(await this.field.totalSoil()).to.be.equal('495'); @@ -179,7 +187,7 @@ describe('Sun', function () { // temperature is 1% await this.field.incrementTotalPodsE('1000'); // add 1 fertilizer owner, 1 fert (which is equal to 5 beans) - await this.fertilizer.connect(owner).addFertilizerOwner('0', '1', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.001'), '0') //sunrise with 1500 beans 500 given to field, silo, and barn this.result = await this.season.sunSunrise('1500', 8); // emit a event that 495 soil was issued at season 3 @@ -205,9 +213,9 @@ describe('Sun', function () { it("1 all and 1 some fertilizable", async function () { await this.field.incrementTotalPodsE(to6('250')); - await this.fertilizer.connect(owner).addFertilizerOwner('0', '40', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('0', to18('0.04'), '0') this.result = await this.season.sunSunrise(to6('120'), 8); - await this.fertilizer.connect(owner).addFertilizerOwner('6374', '40', '0') + await this.fertilizer.connect(owner).addFertilizerOwner('6374', to18('0.04'), '0') this.result = await this.season.sunSunrise(to6('480'), 8); expect(await this.fertilizer.isFertilizing()).to.be.equal(true); @@ -250,8 +258,9 @@ describe('Sun', function () { snapshotId = await takeSnapshot(); - await this.well.setReserves(mockVal[0]); - await this.well.setReserves(mockVal[0]); + await setReserves(owner, this.well, mockVal[0]); + await setReserves(owner, this.well, mockVal[0]); + // Time skip an hour after setting new balance (twap will be very close to whats in mockVal) await timeSkip(START_TIME + 60*60); From 78ed9f4b6edebe7aae70c1c9b6758e32ec64331d Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:04:32 -0400 Subject: [PATCH 67/96] documentation + style updates --- .../beanstalk/barn/FertilizerFacet.sol | 69 ++++++++----------- .../contracts/beanstalk/barn/UnripeFacet.sol | 7 ++ .../mocks/mockFacets/MockFertilizerFacet.sol | 17 +++++ 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index ec0737c7de..71ca0bd753 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -19,7 +19,7 @@ import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; /** * @author Publius - * @title Handles Sprouting Beans from Sprout Tokens + * @title FertilizerFacet handles Minting Fertilizer and Rinsing Sprouts earned from Fertilizer. **/ contract FertilizerFacet { @@ -29,6 +29,8 @@ contract FertilizerFacet { event SetFertilizer(uint128 id, uint128 bpf); + uint256 private constant FERTILIZER_AMOUNT_PRECISION = 1e24; + AppStorage internal s; struct Supply { @@ -36,6 +38,12 @@ contract FertilizerFacet { uint256 supply; } + + /** + * @notice Rinses Rinsable Sprouts earned from Fertilizer. + * @param ids The ids of the Fertilizer to rinse. + * @param mode The balance to transfer Beans to; see {LibTrasfer.To} + */ function claimFertilized(uint256[] calldata ids, LibTransfer.To mode) external payable @@ -44,30 +52,18 @@ contract FertilizerFacet { LibTransfer.sendToken(C.bean(), amount, msg.sender, mode); } - /** - * @dev Returns the amount of Fertilize that can be purchased with `wethAmountIn` WETH. - * Can be used to help calculate `minFertilizerOut` in `mintFertilizer` - */ - function getMintFertilizerOut( - uint256 wethAmountIn - ) external view returns (uint256 fertilizerAmountOut) { - fertilizerAmountOut = wethAmountIn.mul( - LibEthUsdOracle.getEthUsdPrice() - ).div(1e24); - } - /** * @notice Purchase Fertilizer from the Barn Raise with WETH. * @param wethAmountIn Amount of WETH to buy Fertilizer with 18 decimal precision. - * @param minFertilizerOut The minimum amount of Fertilizer to purchase. - * @param minLP The minimum amount of LP to receive after. + * @param minFertilizerOut The minimum amount of Fertilizer to purchase. Protects against a significant ETH/USD price decrease. + * @param minLPTokensOut The minimum amount of LP tokens to receive after adding liquidity with `weth`. * @param mode The balance to transfer Beans to; see {LibTrasfer.To} * @dev The # of Fertilizer minted is equal to the value of the Ether paid in USD. */ function mintFertilizer( uint256 wethAmountIn, uint256 minFertilizerOut, - uint256 minLP, + uint256 minLPTokensOut, LibTransfer.From mode ) external payable returns (uint256 fertilizerAmountOut) { @@ -78,10 +74,7 @@ contract FertilizerFacet { mode ); // return value <= amount, so downcasting is safe. - // Convert from Ether amount with 18 decimals to USD amount with 0 decimals. - fertilizerAmountOut = wethAmountIn.mul( - LibEthUsdOracle.getEthUsdPrice() - ).div(1e24); + fertilizerAmountOut = getMintFertilizerOut(wethAmountIn); require(fertilizerAmountOut >= minFertilizerOut, "Fertilizer Not enough bought."); @@ -92,33 +85,14 @@ contract FertilizerFacet { uint128(s.season.current), wethAmountIn, fertilizerAmountOut, - minLP + minLPTokensOut ); C.fertilizer().beanstalkMint(msg.sender, uint256(id), (fertilizerAmountOut).toUint128(), s.bpf); } /** - * @notice Contributes to Barn Raise on behalf of existing fertilizer holders. + * @dev Callback from Fertilizer contract in `claimFertilized` function. */ - function addFertilizerOwner( - uint128 id, - uint128 amount, - uint256 minLP - ) external payable { - LibDiamond.enforceIsContractOwner(); - IERC20(C.WETH).transferFrom( - msg.sender, - address(this), - uint256(amount) - ); - - uint256 fertilizerAmount = uint256(amount).mul( - LibEthUsdOracle.getEthUsdPrice() - ).div(1e24); - - LibFertilizer.addFertilizer(id, amount, fertilizerAmount, minLP); - } - function payFertilizer(address account, uint256 amount) external payable { require(msg.sender == C.fertilizerAddress()); LibTransfer.sendToken( @@ -129,6 +103,19 @@ contract FertilizerFacet { ); } + /** + * @dev Returns the amount of Fertilize that can be purchased with `wethAmountIn` WETH. + * Can be used to help calculate `minFertilizerOut` in `mintFertilizer`. + * `wethAmountIn` has 18 decimals, `getEthUsdPrice()` has 6 decimals and `fertilizerAmountOut` has 0 decimals. + */ + function getMintFertilizerOut( + uint256 wethAmountIn + ) public view returns (uint256 fertilizerAmountOut) { + fertilizerAmountOut = wethAmountIn.mul( + LibEthUsdOracle.getEthUsdPrice() + ).div(FERTILIZER_AMOUNT_PRECISION); + } + function totalFertilizedBeans() external view returns (uint256 beans) { return s.fertilizedIndex; } diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 568d948895..15851c2f55 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -247,6 +247,13 @@ contract UnripeFacet is ReentrancyGuard { /////////////// UNDERLYING TOKEN MIGRATION ////////////////// + /** + * @notice Adds underlying tokens to an Unripe Token. + * @param unripeToken The Unripe Token to add underlying tokens to. + * @param amount The amount of underlying tokens to add. + * @dev Used to migrate the underlying token of an Unripe Token to a new token. + * Only callable by the contract owner. + */ function addMigratedUnderlying(address unripeToken, uint256 amount) external payable nonReentrant { LibDiamond.enforceIsContractOwner(); IERC20(s.u[unripeToken].underlyingToken).safeTransferFrom( diff --git a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol index 0bc9a6036a..146b631857 100644 --- a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol +++ b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol @@ -14,6 +14,23 @@ import "contracts/beanstalk/barn/FertilizerFacet.sol"; contract MockFertilizerFacet is FertilizerFacet { + function addFertilizerOwner( + uint128 id, + uint128 wethAmountIn, + uint256 minLPOut + ) external payable { + LibDiamond.enforceIsContractOwner(); + IERC20(C.WETH).transferFrom( + msg.sender, + address(this), + uint256(wethAmountIn) + ); + + uint256 fertilizerAmount = getMintFertilizerOut(wethAmountIn); + + LibFertilizer.addFertilizer(id, wethAmountIn, fertilizerAmount, minLPOut); + } + function setPenaltyParams(uint256 recapitalized, uint256 fertilized) external { s.recapitalized = recapitalized; s.fertilizedIndex = fertilized; From c01f2ecef7799cb8ca8f9328b7c2e2ae86e4a8d3 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:08:15 -0400 Subject: [PATCH 68/96] remove addFertilizerOwner function --- protocol/scripts/bips.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/protocol/scripts/bips.js b/protocol/scripts/bips.js index 07db151aaf..b9a2bb19cd 100644 --- a/protocol/scripts/bips.js +++ b/protocol/scripts/bips.js @@ -160,7 +160,10 @@ async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefine "ConvertGettersFacet" ], initFacetName: "InitMigrateUnripeBean3CrvToBeanEth", - selectorsToRemove: [ '0x0bfca7e3' ], + selectorsToRemove: [ + '0x0bfca7e3', + '0x8cd31ca0' + ], bip: false, object: !mock, verbose: verbose, From 6482ed73b37943e49d6e5d825f3a2756f6ff0bfa Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:19:40 -0400 Subject: [PATCH 69/96] update ABI --- protocol/abi/Beanstalk.json | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/protocol/abi/Beanstalk.json b/protocol/abi/Beanstalk.json index 1e59bd6d06..2bac5dc7df 100644 --- a/protocol/abi/Beanstalk.json +++ b/protocol/abi/Beanstalk.json @@ -516,29 +516,6 @@ "name": "SetFertilizer", "type": "event" }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "id", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" - }, - { - "internalType": "uint256", - "name": "minLP", - "type": "uint256" - } - ], - "name": "addFertilizerOwner", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, { "inputs": [ { @@ -883,7 +860,7 @@ }, { "internalType": "uint256", - "name": "minLP", + "name": "minLPTokensOut", "type": "uint256" }, { From 4869bc127ddde351ee1f21dcac4710fe45a48d4a Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:30:41 -0400 Subject: [PATCH 70/96] transfer WETH directly to Well --- .../contracts/beanstalk/barn/FertilizerFacet.sol | 13 +++++++------ protocol/contracts/libraries/LibFertilizer.sol | 10 ++-------- .../mocks/mockFacets/MockFertilizerFacet.sol | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index 71ca0bd753..1555d2c5a5 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -66,13 +66,15 @@ contract FertilizerFacet { uint256 minLPTokensOut, LibTransfer.From mode ) external payable returns (uint256 fertilizerAmountOut) { - - wethAmountIn = LibTransfer.receiveToken( + // Transfer the WETH directly to the Well for gas efficiency purposes. + wethAmountIn = LibTransfer.transferToken( IERC20(C.WETH), - uint256(wethAmountIn), msg.sender, - mode - ); // return value <= amount, so downcasting is safe. + C.BEAN_ETH_WELL, + uint256(wethAmountIn), + mode, + LibTransfer.To.EXTERNAL + ); fertilizerAmountOut = getMintFertilizerOut(wethAmountIn); @@ -83,7 +85,6 @@ contract FertilizerFacet { uint128 id = LibFertilizer.addFertilizer( uint128(s.season.current), - wethAmountIn, fertilizerAmountOut, minLPTokensOut ); diff --git a/protocol/contracts/libraries/LibFertilizer.sol b/protocol/contracts/libraries/LibFertilizer.sol index f59cbfb6ea..718c0687a2 100644 --- a/protocol/contracts/libraries/LibFertilizer.sol +++ b/protocol/contracts/libraries/LibFertilizer.sol @@ -35,7 +35,6 @@ library LibFertilizer { function addFertilizer( uint128 season, - uint256 amount, uint256 fertilizerAmount, uint256 minLP ) internal returns (uint128 id) { @@ -54,7 +53,7 @@ library LibFertilizer { s.fertilizer[id] = s.fertilizer[id].add(fertilizerAmount128); s.activeFertilizer = s.activeFertilizer.add(fertilizerAmount); // Add underlying to Unripe Beans and Unripe LP - addUnderlying(amount, fertilizerAmount.mul(DECIMALS), minLP); + addUnderlying(fertilizerAmount.mul(DECIMALS), minLP); // If not first time adding Fertilizer with this id, return if (s.fertilizer[id] > fertilizerAmount128) return id; // If first time, log end Beans Per Fertilizer and add to Season queue. @@ -73,7 +72,7 @@ library LibFertilizer { humidity = RESTART_HUMIDITY.sub(humidityDecrease); } - function addUnderlying(uint256 amount, uint256 usdAmount, uint256 minAmountOut) internal { + function addUnderlying(uint256 usdAmount, uint256 minAmountOut) internal { AppStorage storage s = LibAppStorage.diamondStorage(); // Calculate how many new Deposited Beans will be minted uint256 percentToFill = usdAmount.mul(C.precision()).div( @@ -106,11 +105,6 @@ library LibFertilizer { newDepositedLPBeans ); - IERC20(C.WETH).transfer( - address(C.BEAN_ETH_WELL), - amount - ); - uint256 newLP = IWell(C.BEAN_ETH_WELL).sync( address(this), minAmountOut diff --git a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol index 146b631857..122f0a7104 100644 --- a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol +++ b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol @@ -22,13 +22,13 @@ contract MockFertilizerFacet is FertilizerFacet { LibDiamond.enforceIsContractOwner(); IERC20(C.WETH).transferFrom( msg.sender, - address(this), + C.BEAN_ETH_WELL, uint256(wethAmountIn) ); uint256 fertilizerAmount = getMintFertilizerOut(wethAmountIn); - LibFertilizer.addFertilizer(id, wethAmountIn, fertilizerAmount, minLPOut); + LibFertilizer.addFertilizer(id, fertilizerAmount, minLPOut); } function setPenaltyParams(uint256 recapitalized, uint256 fertilized) external { From 5066c4a9b6f3b912dac2cdb1ca92549b8f67cc72 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:35:51 -0400 Subject: [PATCH 71/96] add comment to --- protocol/contracts/libraries/LibFertilizer.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protocol/contracts/libraries/LibFertilizer.sol b/protocol/contracts/libraries/LibFertilizer.sol index 718c0687a2..356941d794 100644 --- a/protocol/contracts/libraries/LibFertilizer.sol +++ b/protocol/contracts/libraries/LibFertilizer.sol @@ -72,6 +72,10 @@ library LibFertilizer { humidity = RESTART_HUMIDITY.sub(humidityDecrease); } + /** + * @dev Any WETH contributions should already be transferred to the Bean:Eth Well to allow for a gas efficient liquidity + * addition through the use of `sync`. See {FertilizerFacet.mintFertilizer} for an example. + */ function addUnderlying(uint256 usdAmount, uint256 minAmountOut) internal { AppStorage storage s = LibAppStorage.diamondStorage(); // Calculate how many new Deposited Beans will be minted From 33e551c7f6de77e57b3627ff2ff28aed86dfc673 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 17:39:30 -0400 Subject: [PATCH 72/96] update comments --- protocol/contracts/beanstalk/barn/FertilizerFacet.sol | 2 +- protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index 1555d2c5a5..2a7ab72161 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -66,7 +66,7 @@ contract FertilizerFacet { uint256 minLPTokensOut, LibTransfer.From mode ) external payable returns (uint256 fertilizerAmountOut) { - // Transfer the WETH directly to the Well for gas efficiency purposes. + // Transfer the WETH directly to the Well for gas efficiency purposes. The WETH is later synced in {LibFertilizer.addUnderlying}. wethAmountIn = LibTransfer.transferToken( IERC20(C.WETH), msg.sender, diff --git a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol index 122f0a7104..392e6adf44 100644 --- a/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol +++ b/protocol/contracts/mocks/mockFacets/MockFertilizerFacet.sol @@ -20,6 +20,7 @@ contract MockFertilizerFacet is FertilizerFacet { uint256 minLPOut ) external payable { LibDiamond.enforceIsContractOwner(); + // Transfer the WETH directly to the Well for gas efficiency purposes. The WETH is later synced in {LibFertilizer.addUnderlying}. IERC20(C.WETH).transferFrom( msg.sender, C.BEAN_ETH_WELL, From c011dff28327953e2ae3a3dcd16f7a9b9879335b Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 22:06:35 -0400 Subject: [PATCH 73/96] add tests to demonstrate success after migration --- .../test/Bean3CrvToBeanEthMigration.test.js | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/protocol/test/Bean3CrvToBeanEthMigration.test.js b/protocol/test/Bean3CrvToBeanEthMigration.test.js index 5970679f8f..89ad56cbbd 100644 --- a/protocol/test/Bean3CrvToBeanEthMigration.test.js +++ b/protocol/test/Bean3CrvToBeanEthMigration.test.js @@ -7,10 +7,11 @@ const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); const { getBeanstalk } = require('../utils/contracts.js'); const { impersonateBeanstalkOwner, impersonateSigner } = require('../utils/signer.js'); const { ethers } = require('hardhat'); -const { mintEth } = require('../utils/mint.js'); +const { mintEth, mintBeans } = require('../utils/mint.js'); const { ConvertEncoder } = require('./utils/encoder.js'); const { setReserves } = require('../utils/well.js'); const { toBN } = require('../utils/helpers.js'); +const { impersonateBean } = require('../scripts/impersonate.js'); let user,user2,owner; let publius; @@ -145,5 +146,37 @@ describe('Bean:3Crv to Bean:Eth Migration', function () { expect(await this.beanstalk.getTotalUnderlying(UNRIPE_LP)).to.be.equal(beanEthUnderlying) expect(await this.beanstalk.getUnderlying(UNRIPE_LP, await this.unripeLp.totalSupply())).to.be.equal(beanEthUnderlying) }) + + describe('Interactions with Unripe succeed', async function () { + it('chop succeeds', async function () { + await this.beanstalk.connect(publius).withdrawDeposit(UNRIPE_LP, '-56836', to6('1'), 1); + await this.beanstalk.connect(publius).chop(UNRIPE_LP, to6('1'), 1, 0); + }) + + it('deposit succeeds', async function () { + await this.beanstalk.connect(publius).withdrawDeposit(UNRIPE_LP, '-56836', to6('1'), 1); + await this.beanstalk.connect(publius).deposit(UNRIPE_LP, to6('1'), 1); + }) + + it('enrootDeposit succeeds', async function () { + await this.beanstalk.connect(publius).enrootDeposit(UNRIPE_LP, '-56836', to6('1')); + }) + + it('enrootDeposits succeeds', async function () { + await this.beanstalk.connect(publius).enrootDeposits(UNRIPE_LP, ['-56836'], [to6('1')]); + }) + + it('convert Unripe Bean to LP succeeds', async function () { + await this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeBeansToLP(to6('200'), '0'), ['-16272'], [to6('200')]); + }) + + it('convert Unripe LP to Bean succeeds', async function () { + await impersonateBean() + await this.bean.mint(user.address, to6('100000')) + await this.bean.connect(user).approve(BEAN_ETH_WELL, to6('100000')) + await this.beanEth.connect(user).addLiquidity([to6('100000'), '0'], '0', user.address, ethers.constants.MaxUint256); + await this.beanstalk.connect(publius).convert(ConvertEncoder.convertUnripeLPToBeans(to6('200'), '0'), ['-56836'], [to6('200')]) + }) + }) }) }) \ No newline at end of file From 515fd395ac6b77ebdc5d9d42130a3d738533a691 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 11 Sep 2023 22:33:48 -0400 Subject: [PATCH 74/96] more convert tests --- protocol/test/ConvertUnripe.test.js | 120 ++++++++++++++-------------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/protocol/test/ConvertUnripe.test.js b/protocol/test/ConvertUnripe.test.js index d77e2e8c74..decc0a243e 100644 --- a/protocol/test/ConvertUnripe.test.js +++ b/protocol/test/ConvertUnripe.test.js @@ -54,7 +54,7 @@ describe('Unripe Convert', function () { await this.wellToken.connect(user2).approve(this.silo.address, ethers.constants.MaxUint256); await this.well.connect(user).addLiquidity( - [toBean('10000'), to18('10')], + [toBean('1000000'), to18('1000')], 0, owner.address, ethers.constants.MaxUint256 @@ -65,7 +65,7 @@ describe('Unripe Convert', function () { this.unripeLP = await ethers.getContractAt('MockToken', UNRIPE_LP) this.fertilizer = await ethers.getContractAt('MockFertilizerFacet', this.diamond.address) await this.unripeBean.mint(userAddress, to6('10000')) - await this.unripeLP.mint(userAddress, to6('31.622776')) + await this.unripeLP.mint(userAddress, to6('3162.277660')) await this.unripeBean.connect(user).approve(this.diamond.address, to18('100000000')) await this.unripeLP.connect(user).approve(this.diamond.address, to18('100000000')) await this.fertilizer.setFertilizerE(true, to6('10000')) @@ -79,7 +79,7 @@ describe('Unripe Convert', function () { ) await this.unripe.connect(owner).addUnderlying( UNRIPE_LP, - to18('31.622776') // 31.622776601683793319 + to18('3162.277660') // 3162.2776601683793319 ) }); @@ -139,7 +139,7 @@ describe('Unripe Convert', function () { user.address, ethers.constants.MaxUint256 ); - expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal(to6('30.182395')); + expect(await this.convertGet.getMaxAmountIn(UNRIPE_LP, UNRIPE_BEAN)).to.be.equal(to6('31.606981')); }); }) @@ -188,29 +188,29 @@ describe('Unripe Convert', function () { it('properly updates total values', async function () { expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1000')); expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100')); - expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('474652298'); - const bdv = await this.silo.bdv(this.unripeLP.address, '474652298') + expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq('4711829'); + const bdv = await this.silo.bdv(this.unripeLP.address, '4711829') expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(bdv); expect(await this.silo.totalStalk()).to.eq(toStalk('100').add(bdv.mul(to6('0.01')))); }); it('properly updates user values -test', async function () { - const bdv = await this.silo.bdv(this.unripeLP.address, '474652298') + const bdv = await this.silo.bdv(this.unripeLP.address, '4711829') expect(await this.silo.balanceOfStalk(userAddress)).to.eq(toStalk('100').add(bdv.mul(to6('0.01')))); }); it('properly updates user deposits', async function () { expect((await this.silo.getDeposit(userAddress, this.unripeBean.address, 0))[0]).to.eq(to6('1000')); const deposit = await this.silo.getDeposit(userAddress, this.unripeLP.address, 0); - expect(deposit[0]).to.eq('474652298'); - expect(deposit[1]).to.eq(await this.silo.bdv(this.unripeLP.address, '474652298')); + expect(deposit[0]).to.eq('4711829'); + expect(deposit[1]).to.eq(await this.silo.bdv(this.unripeLP.address, '4711829')); }); it('emits events', async function () { await expect(this.result).to.emit(this.silo, 'RemoveDeposits') .withArgs(userAddress, this.unripeBean.address, [0], [to6('1000')], to6('1000'), [to6('100')]); await expect(this.result).to.emit(this.silo, 'AddDeposit') - .withArgs(userAddress, this.unripeLP.address, 0, '474652298', await this.silo.bdv(this.unripeLP.address, '474652298')); + .withArgs(userAddress, this.unripeLP.address, 0, '4711829', await this.silo.bdv(this.unripeLP.address, '4711829')); }); }); @@ -361,59 +361,61 @@ describe('Unripe Convert', function () { // }) }); -// describe('convert lp to beans', async function () { -// beforeEach(async function () { -// await this.season.teleportSunrise(10); -// this.season.deployStemsUpgrade(); -// }); + describe('convert lp to beans', async function () { + beforeEach(async function () { + await this.season.teleportSunrise(10); + this.season.deployStemsUpgrade(); + }); -// describe('revert', async function () { -// it('not enough Beans', async function () { -// await this.well.connect(user).addLiquidity( -// [toBean('200'), '0'], -// '0', -// user.address, -// ethers.constants.MaxUint256 -// ); -// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); -// await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) -// .to.be.revertedWith('Curve: Insufficient Output'); -// }); + describe('revert', async function () { + it('not enough Beans', async function () { + await this.well.connect(user).addLiquidity( + [toBean('200'), '0'], + '0', + user.address, + ethers.constants.MaxUint256 + ); + await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); + await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) + .to.be.revertedWith(''); + }); -// it('p >= 1', async function () { -// await this.well.connect(user).addLiquidity([toBean('0'), to18('1')], to18('0.5')); -// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); -// await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) -// .to.be.revertedWith('Convert: P must be < 1.'); -// }); -// }); + it('p >= 1', async function () { + await this.well.connect(user).addLiquidity([toBean('0'), to18('1')], to18('0.5'), user.address, ethers.constants.MaxUint256); + await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); + await expect(this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('2000'), to6('2500')), ['0'], [to6('2000')])) + .to.be.revertedWith('Convert: P must be < 1.'); + }); + }); -// describe('below max', function () { -// beforeEach(async function () { -// await this.well.connect(user).addLiquidity( -// [toBean('200'), '0'], -// '0', -// user.address, -// ethers.constants.MaxUint256 -// ); -// await this.silo.connect(user).deposit(this.unripeLP.address, to6('1000'), EXTERNAL); -// this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('1000'), to6('990')), ['0'], [to6('1000')]) -// }); + describe('below max', function () { + beforeEach(async function () { + await this.well.connect(user).addLiquidity( + [toBean('200'), '0'], + '0', + user.address, + ethers.constants.MaxUint256 + ); + await this.silo.connect(user).deposit(this.unripeLP.address, to6('3'), EXTERNAL); + this.bdv = await this.silo.getTotalDepositedBdv(this.unripeLP.address); + this.result = await this.convert.connect(user).convert(ConvertEncoder.convertUnripeLPToBeans(to6('3'), toBN('0')), ['0'], [to6('1000')]) + }); -// it('properly updates total values', async function () { -// expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq(to6('1006.18167')); -// expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(to6('100.618167')); -// expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); -// expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); -// //expect(await this.silo.totalSeeds()).to.eq(to6('201.236334')); -// expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); -// }); + it('properly updates total values', async function () { + const bdv = await this.silo.bdv(this.unripeBean.address, '636776401') + expect(await this.silo.getTotalDeposited(this.unripeBean.address)).to.eq('636776401'); + expect(await this.silo.getTotalDepositedBdv(this.unripeBean.address)).to.eq(this.bdv); + expect(await this.silo.getTotalDeposited(this.unripeLP.address)).to.eq(to6('0')); + expect(await this.silo.getTotalDepositedBdv(this.unripeLP.address)).to.eq(to6('0')); + //expect(await this.silo.totalSeeds()).to.eq(to6('201.236334')); + expect(await this.silo.totalStalk()).to.eq(this.bdv.mul('10000')); + }); -// it('properly updates user values', async function () { -// //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('201.236334')); -// expect(await this.silo.totalStalk()).to.eq(toStalk('100.618167')); -// }); -// }); + it('properly updates user values', async function () { + //expect(await this.silo.balanceOfSeeds(userAddress)).to.eq(to6('201.236334')); + expect(await this.silo.totalStalk()).to.eq(this.bdv.mul('10000')); + }); + }); // //these tests use the new 2 seeds per bdv instead of previous 4 (note in the beforeEach above that deployStemsUpgrade is called) // describe('multiple crates', function () { @@ -522,5 +524,5 @@ describe('Unripe Convert', function () { // expect(await this.silo.totalStalk()).to.eq(toStalk('200')); // }); // }); -// }); + }); }); From 78673206974ec45a7837c2cea8daa8370fc36e1f Mon Sep 17 00:00:00 2001 From: alecks <0xalecks@gmail.com> Date: Wed, 20 Sep 2023 10:09:42 -0400 Subject: [PATCH 75/96] protocol: add bip38 migration script --- protocol/hardhat.config.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/protocol/hardhat.config.js b/protocol/hardhat.config.js index 7513790a17..5aa013e896 100644 --- a/protocol/hardhat.config.js +++ b/protocol/hardhat.config.js @@ -12,6 +12,11 @@ require("@openzeppelin/hardhat-upgrades"); require("dotenv").config(); require("hardhat-contract-sizer"); +// BIP 38 migration ---- +const { bipMigrateUnripeBean3CrvToBeanEth } = require("./scripts/bips.js"); +const { finishBeanEthMigration } = require("./scripts/beanEthMigration.js"); +// ---- + const { upgradeWithNewFacets } = require("./scripts/diamond"); const { impersonateSigner, @@ -201,6 +206,11 @@ task("beanstalkAdmin", async function () { await mockBeanstalkAdmin(); }); +task("migrate-bip38", async function () { + await bipMigrateUnripeBean3CrvToBeanEth(); + await finishBeanEthMigration(); +}); + //////////////////////// SUBTASK CONFIGURATION //////////////////////// // Add a subtask that sets the action for the TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS task @@ -254,7 +264,7 @@ module.exports = { chainId: 5, url: process.env.GOERLI_RPC || "", timeout: 100000 - }, + } }, etherscan: { apiKey: process.env.ETHERSCAN_KEY From 0a1b6d1c71fdb6304ed78ef5e1cf470feb67f898 Mon Sep 17 00:00:00 2001 From: Brean0 Date: Mon, 18 Sep 2023 20:05:18 +0900 Subject: [PATCH 76/96] change metadata - add urBEANETH support - remove urBEAN3CRV - rename deposit token names to better standardize --- projects/ui/src/graph/graphql.schema.json | 3038 ++++++++++++++++- .../beanstalk/metadata/MetadataImage.sol | 66 +- protocol/test/data/base64EncodedImageBean.txt | 2 +- .../test/data/base64EncodedImageBean3Crv.txt | 2 +- .../test/data/base64EncodedImageBeanEth.txt | 2 +- .../test/data/base64EncodedImageUrBean.txt | 2 +- .../data/base64EncodedImageUrBean3Crv.txt | 1 - .../data/base64EncodedImageUrBean3Crv2.txt | 1 - .../test/data/base64EncodedImageUrBeanEth.txt | 1 + 9 files changed, 3071 insertions(+), 44 deletions(-) delete mode 100644 protocol/test/data/base64EncodedImageUrBean3Crv.txt delete mode 100644 protocol/test/data/base64EncodedImageUrBean3Crv2.txt create mode 100644 protocol/test/data/base64EncodedImageUrBeanEth.txt diff --git a/projects/ui/src/graph/graphql.schema.json b/projects/ui/src/graph/graphql.schema.json index 0cbf867354..5a41d47910 100644 --- a/projects/ui/src/graph/graphql.schema.json +++ b/projects/ui/src/graph/graphql.schema.json @@ -16572,6 +16572,22 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "overall", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "pool", "description": null, @@ -17436,6 +17452,70 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "overall", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "overall_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "overall_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "overall_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "pool", "description": null, @@ -18817,6 +18897,12 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "overall", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "pool", "description": null, @@ -105134,6 +105220,176 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "wellOracle", + "description": null, + "args": [ + { + "name": "block", + "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "type": { + "kind": "INPUT_OBJECT", + "name": "Block_height", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subgraphError", + "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "_SubgraphErrorPolicy_", + "ofType": null + } + }, + "defaultValue": "deny", + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "wellOracles", + "description": null, + "args": [ + { + "name": "block", + "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "type": { + "kind": "INPUT_OBJECT", + "name": "Block_height", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "100", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "orderBy", + "description": null, + "type": { + "kind": "ENUM", + "name": "WellOracle_orderBy", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "orderDirection", + "description": null, + "type": { + "kind": "ENUM", + "name": "OrderDirection", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "skip", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "0", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subgraphError", + "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "_SubgraphErrorPolicy_", + "ofType": null + } + }, + "defaultValue": "deny", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "where", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "whitelistToken", "description": null, @@ -125251,6 +125507,11 @@ "name": "StalkChange", "ofType": null }, + { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + }, { "kind": "OBJECT", "name": "WhitelistToken", @@ -130817,9 +131078,41 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "fourPointFiveSeedBeanAPY", + "description": "Bean APY for 4.5 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY", + "description": "Stalk APY for 4.5 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "fourSeedBeanAPY", - "description": "Bean APY for four seeds per BDV", + "description": "Bean APY for 4 seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -130835,7 +131128,7 @@ }, { "name": "fourSeedStalkAPY", - "description": "Stalk APY for four seeds per BDV", + "description": "Stalk APY for 4 seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -130881,9 +131174,73 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "threePointTwoFiveSeedBeanAPY", + "description": "Bean APY for 3.25 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY", + "description": "Stalk APY for 3.25 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY", + "description": "Bean APY for 3 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY", + "description": "Stalk APY for 3 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "twoSeedBeanAPY", - "description": "Bean APY for two seeds per BDV", + "description": "Bean APY for 2 seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -130899,7 +131256,7 @@ }, { "name": "twoSeedStalkAPY", - "description": "Stalk APY for two seeds per BDV", + "description": "Stalk APY for 2 seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -130928,6 +131285,22 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY", + "description": "Bean APY for 0 seeds per BDV", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -131305,6 +131678,230 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "fourPointFiveSeedBeanAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedBeanAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "fourSeedBeanAPY", "description": null, @@ -131769,6 +132366,454 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "threePointTwoFiveSeedBeanAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedBeanAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "twoSeedBeanAPY", "description": null, @@ -132104,6 +133149,118 @@ "defaultValue": null, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigDecimal", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null } ], "interfaces": null, @@ -132136,6 +133293,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "fourPointFiveSeedBeanAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fourPointFiveSeedStalkAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "fourSeedBeanAPY", "description": null, @@ -132160,6 +133329,30 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "threePointTwoFiveSeedBeanAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threePointTwoFiveSeedStalkAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedBeanAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "threeSeedStalkAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "twoSeedBeanAPY", "description": null, @@ -132177,6 +133370,12 @@ "description": null, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "zeroSeedBeanAPY", + "description": null, + "isDeprecated": false, + "deprecationReason": null } ], "possibleTypes": null @@ -147108,6 +148307,176 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "wellOracle", + "description": null, + "args": [ + { + "name": "block", + "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "type": { + "kind": "INPUT_OBJECT", + "name": "Block_height", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subgraphError", + "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "_SubgraphErrorPolicy_", + "ofType": null + } + }, + "defaultValue": "deny", + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "wellOracles", + "description": null, + "args": [ + { + "name": "block", + "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "type": { + "kind": "INPUT_OBJECT", + "name": "Block_height", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "100", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "orderBy", + "description": null, + "type": { + "kind": "ENUM", + "name": "WellOracle_orderBy", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "orderDirection", + "description": null, + "type": { + "kind": "ENUM", + "name": "OrderDirection", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "skip", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "0", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subgraphError", + "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "_SubgraphErrorPolicy_", + "ofType": null + } + }, + "defaultValue": "deny", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "where", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "WellOracle", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "whitelistToken", "description": null, @@ -148967,6 +150336,1667 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "WellOracle", + "description": null, + "fields": [ + { + "name": "blockNumber", + "description": " Block number of this event ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt", + "description": " Timestamp of this event ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves", + "description": " Time weighted cumulative reserves ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB", + "description": " DeltaB for season", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash", + "description": " Transaction hash of the transaction that emitted this event ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": "wellOracle-{ Transaction hash }-{ Log index }", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex", + "description": " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol", + "description": " The protocol this transaction belongs to ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Beanstalk", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season", + "description": " Season of oracle ", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "SiloEvent", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "_change_block", + "description": "Filter for the block changed event.", + "type": { + "kind": "INPUT_OBJECT", + "name": "BlockChangedFilter", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "and", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "blockNumber_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_not_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Bytes", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "BigInt", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_contains_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_ends_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_ends_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_contains_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_ends_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_ends_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_starts_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_not_starts_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_starts_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash_starts_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "or", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "WellOracle_filter", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "Beanstalk_filter", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_contains_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_ends_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_ends_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_contains", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_contains_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_ends_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_ends_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_starts_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_not_starts_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_starts_with", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol_starts_with_nocase", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_gt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_gte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_lt", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_lte", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_not", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season_not_in", + "description": null, + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "WellOracle_orderBy", + "description": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "blockNumber", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cumulativeReserves", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deltaB", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "hash", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logIndex", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__id", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__lastSeason", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__lastUpgrade", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__methodologyVersion", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__name", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__schemaVersion", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__slug", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "protocol__subgraphVersion", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season", + "description": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, { "kind": "OBJECT", "name": "WhitelistToken", diff --git a/protocol/contracts/beanstalk/metadata/MetadataImage.sol b/protocol/contracts/beanstalk/metadata/MetadataImage.sol index 0977878f5b..8e7989c67f 100644 --- a/protocol/contracts/beanstalk/metadata/MetadataImage.sol +++ b/protocol/contracts/beanstalk/metadata/MetadataImage.sol @@ -71,8 +71,8 @@ contract MetadataImage { beanToken(), bean3CRVToken(), urBeanToken(), - urBean3CRVToken(), beanETHCP2WellToken(), + urBeanETHCP2WellToken(), fullLeafRow(), '' )); @@ -409,36 +409,22 @@ contract MetadataImage { return beanTemplateToken(false); } - function bean3CRVToken() internal pure returns (string memory) { - return beanLPTemplateToken(false); - } - function urBeanToken() internal pure returns (string memory) { return beanTemplateToken(true); } - function urBean3CRVToken() internal pure returns (string memory) { - return beanLPTemplateToken(true); + function beanETHCP2WellToken() internal pure returns (string memory) { + return beanETHCP2WellTemplateToken(false); } - function beanTemplateToken(bool ripe) internal pure returns (string memory) { - return string(abi.encodePacked( - '', - '' - ) - ); + function urBeanETHCP2WellToken() internal pure returns (string memory) { + return beanETHCP2WellTemplateToken(true); } - function beanLPTemplateToken(bool ripe) internal pure returns (string memory) { + function bean3CRVToken() internal pure returns (string memory) { return string(abi.encodePacked( - '', '', '', @@ -448,21 +434,33 @@ contract MetadataImage { '' ) ); - } + } - function beanETHCP2WellToken() internal pure returns (string memory) { + function beanTemplateToken(bool ripe) internal pure returns (string memory) { + return string(abi.encodePacked( + '', + '' + ) + ); + } + + function beanETHCP2WellTemplateToken(bool ripe) internal pure returns (string memory) { return string(abi.encodePacked( - '', - '', - '', - '', + '', '', '' ) ); } - function useAssetTransform(string memory assetName, int256 x, int256 y) internal pure returns (string memory) { return string(abi.encodePacked( ' Date: Mon, 18 Sep 2023 20:06:18 +0900 Subject: [PATCH 77/96] update tests --- protocol/test/Silo.test.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/protocol/test/Silo.test.js b/protocol/test/Silo.test.js index 3538c5057a..0bce531ab6 100644 --- a/protocol/test/Silo.test.js +++ b/protocol/test/Silo.test.js @@ -362,28 +362,28 @@ describe('Silo', function () { it("properly gives an URI", async function () { await this.season.farmSunrises(1000); + // bean token depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBean.txt', 'utf-8'); depositID1 = '0xBEA0000029AD1c77D3d5D23Ba2D8893dB9d1Efab000000000000000000000002'; expect(await this.metadata.uri(depositID1)).to.eq(depositmetadata); + // bean3crv token depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBean3Crv.txt', 'utf-8'); depositID2 = '0xC9C32CD16BF7EFB85FF14E0C8603CC90F6F2EE49000000000000000000000200'; expect(await this.metadata.uri(depositID2)).to.eq(depositmetadata); - depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBean.txt', 'utf-8'); - depositID3 = '0x1BEA0050E63e05FBb5D8BA2f10cf5800B6224449000000000000000000000400'; + // beanEthToken + depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBeanEth.txt', 'utf-8'); + depositID3 = '0xBEA0e11282e2bB5893bEcE110cF199501e872bAdFFFFFFFFFFFFF00000000002'; expect(await this.metadata.uri(depositID3)).to.eq(depositmetadata); - - depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBean3Crv.txt', 'utf-8'); - depositID4 = '0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716DFFFFFFFFFFFFFFFFFFFFF97C'; - expect(await this.metadata.uri(depositID4)).to.eq(depositmetadata); - - depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBean3Crv2.txt', 'utf-8'); - depositID4 = '0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716DFFF000000000000000000111'; + // urBean token + depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBean.txt', 'utf-8'); + depositID4 = '0x1BEA0050E63e05FBb5D8BA2f10cf5800B6224449000000000000000000000400'; expect(await this.metadata.uri(depositID4)).to.eq(depositmetadata); - depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBeanEth.txt', 'utf-8'); - depositID5 = '0xBEA0e11282e2bB5893bEcE110cF199501e872bAdFFFFFFFFFFFFF00000000002'; + // urBeanEth token + depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageUrBeanEth.txt', 'utf-8'); + depositID5 = '0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716DFFFFFFFFFFFFFFFFFFFFF97C'; expect(await this.metadata.uri(depositID5)).to.eq(depositmetadata); }); From 3da3d734343abbddc69f7d6946c0bcbb5543432f Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 18 Sep 2023 11:50:18 -0400 Subject: [PATCH 78/96] Add SwitchUnderlyingToken event and switchUnderlyingToken function --- protocol/abi/Beanstalk.json | 37 +++++++++++++++++++ protocol/contracts/C.sol | 4 +- .../contracts/beanstalk/barn/UnripeFacet.sol | 14 +++++++ .../InitMigrateUnripeBean3CrvToBeanEth.sol | 2 +- protocol/contracts/libraries/LibUnripe.sol | 11 ++++++ 5 files changed, 65 insertions(+), 3 deletions(-) diff --git a/protocol/abi/Beanstalk.json b/protocol/abi/Beanstalk.json index 2bac5dc7df..d9f419d093 100644 --- a/protocol/abi/Beanstalk.json +++ b/protocol/abi/Beanstalk.json @@ -99,6 +99,25 @@ "name": "Pick", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "underlyingToken", + "type": "address" + } + ], + "name": "SwitchUnderlyingToken", + "type": "event" + }, { "inputs": [ { @@ -497,6 +516,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "unripeToken", + "type": "address" + }, + { + "internalType": "address", + "name": "newUnderlyingToken", + "type": "address" + } + ], + "name": "switchUnderlyingToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "anonymous": false, "inputs": [ diff --git a/protocol/contracts/C.sol b/protocol/contracts/C.sol index 569df18015..cdfcec97e7 100644 --- a/protocol/contracts/C.sol +++ b/protocol/contracts/C.sol @@ -78,8 +78,8 @@ library C { //////////////////// Well //////////////////// uint256 internal constant WELL_MINIMUM_BEAN_BALANCE = 1000_000_000; // 1,000 Beans - address constant internal BEANSTALK_PUMP = 0xBA510f10E3095B83a0F33aa9ad2544E22570a87C; - address constant BEAN_ETH_WELL = 0xBEA0e11282e2bB5893bEcE110cF199501e872bAd; + address internal constant BEANSTALK_PUMP = 0xBA510f10E3095B83a0F33aa9ad2544E22570a87C; + address internal constant BEAN_ETH_WELL = 0xBEA0e11282e2bB5893bEcE110cF199501e872bAd; function getSeasonPeriod() internal pure returns (uint256) { return CURRENT_SEASON_PERIOD; diff --git a/protocol/contracts/beanstalk/barn/UnripeFacet.sol b/protocol/contracts/beanstalk/barn/UnripeFacet.sol index 15851c2f55..63f79ddb10 100644 --- a/protocol/contracts/beanstalk/barn/UnripeFacet.sol +++ b/protocol/contracts/beanstalk/barn/UnripeFacet.sol @@ -35,6 +35,8 @@ contract UnripeFacet is ReentrancyGuard { event ChangeUnderlying(address indexed token, int256 underlying); + event SwitchUnderlyingToken(address indexed token, address indexed underlyingToken); + event Chop( address indexed account, address indexed token, @@ -263,4 +265,16 @@ contract UnripeFacet is ReentrancyGuard { ); LibUnripe.incrementUnderlying(unripeToken, amount); } + + /** + * @notice Switches the Underlying Token of an Unripe Token. + * @param unripeToken The Unripe Token to switch the underlying token of. + * @param newUnderlyingToken The new underlying token to switch to. + * @dev `s.u[unripeToken].balanceOfUnderlying` must be 0. + */ + function switchUnderlyingToken(address unripeToken, address newUnderlyingToken) external payable { + LibDiamond.enforceIsContractOwner(); + require(s.u[unripeToken].balanceOfUnderlying == 0, "Unripe: Underlying balance > 0"); + LibUnripe.switchUnderlyingToken(unripeToken, newUnderlyingToken); + } } diff --git a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol index 8b1d77b910..b4ebadd749 100644 --- a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol +++ b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol @@ -26,6 +26,6 @@ contract InitMigrateUnripeBean3CrvToBeanEth { balanceOfUnderlying ); LibUnripe.decrementUnderlying(C.UNRIPE_LP, balanceOfUnderlying); - s.u[C.UNRIPE_LP].underlyingToken = C.BEAN_ETH_WELL; + LibUnripe.switchUnderlyingToken(C.UNRIPE_LP, C.BEAN_ETH_WELL); } } \ No newline at end of file diff --git a/protocol/contracts/libraries/LibUnripe.sol b/protocol/contracts/libraries/LibUnripe.sol index d1ec2a1195..66744070b2 100644 --- a/protocol/contracts/libraries/LibUnripe.sol +++ b/protocol/contracts/libraries/LibUnripe.sol @@ -16,6 +16,7 @@ library LibUnripe { using SafeMath for uint256; event ChangeUnderlying(address indexed token, int256 underlying); + event SwitchUnderlyingToken(address indexed token, address indexed underlyingToken); uint256 constant DECIMALS = 1e6; @@ -94,4 +95,14 @@ library LibUnripe { } decrementUnderlying(token, underlying); } + + /** + * @dev Switches the underlying token of an unripe token. + * Should only be called if `s.u[unripeToken].balanceOfUnderlying == 0`. + */ + function switchUnderlyingToken(address unripeToken, address newUnderlyingToken) internal { + AppStorage storage s = LibAppStorage.diamondStorage(); + s.u[unripeToken].underlyingToken = newUnderlyingToken; + emit SwitchUnderlyingToken(unripeToken, newUnderlyingToken); + } } From 237e8270af8e92279916517eb1b1b03b448d2042 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 18 Sep 2023 11:50:42 -0400 Subject: [PATCH 79/96] Add switch underlying token tests --- protocol/test/Unripe.test.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/protocol/test/Unripe.test.js b/protocol/test/Unripe.test.js index 0d71d638ad..b72df042c2 100644 --- a/protocol/test/Unripe.test.js +++ b/protocol/test/Unripe.test.js @@ -2,7 +2,7 @@ const { expect } = require('chai') const { EXTERNAL, INTERNAL, INTERNAL_EXTERNAL, INTERNAL_TOLERANT } = require('./utils/balances.js') const { deploy } = require('../scripts/deploy.js') const { takeSnapshot, revertToSnapshot } = require("./utils/snapshot") -const { BEAN, UNRIPE_BEAN, UNRIPE_LP } = require('./utils/constants') +const { BEAN, UNRIPE_BEAN, UNRIPE_LP, USDT } = require('./utils/constants') const { to6, to18, toStalk } = require('./utils/helpers.js') const ZERO_BYTES = ethers.utils.formatBytes32String('0x0') @@ -203,4 +203,27 @@ describe('Unripe', function () { ) }) }) + + describe('change underlying', async function () { + it('changes underlying token', async function () { + this.result = await this.unripe.connect(owner).switchUnderlyingToken(UNRIPE_BEAN, USDT) + expect(await this.unripe.getUnderlyingToken(UNRIPE_BEAN)).to.be.equal(USDT) + await expect(this.result).to.emit(this.unripe, 'SwitchUnderlyingToken').withArgs( + UNRIPE_BEAN, + USDT + ) + }) + + it('reverts if underlying balance > 0', async function () { + await this.unripe.connect(owner).addUnderlying( + UNRIPE_BEAN, + to6('100') + ) + await expect(this.unripe.connect(owner).switchUnderlyingToken(UNRIPE_BEAN, USDT)).to.be.revertedWith('Unripe: Underlying balance > 0') + }) + + it('reverts if not owner', async function () { + await expect(this.unripe.connect(user).switchUnderlyingToken(UNRIPE_BEAN, USDT)).to.be.revertedWith('LibDiamond: Must be contract owner') + }) + }) }) \ No newline at end of file From 2143faf7d2ae1013b491956d62bea0d2373a1269 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 14:54:16 -0400 Subject: [PATCH 80/96] reset withdraw seasons in InitMigrateUnripeBean3CrvToBeanEth --- .../beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol index b4ebadd749..a3e0743dfa 100644 --- a/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol +++ b/protocol/contracts/beanstalk/init/InitMigrateUnripeBean3CrvToBeanEth.sol @@ -27,5 +27,8 @@ contract InitMigrateUnripeBean3CrvToBeanEth { ); LibUnripe.decrementUnderlying(C.UNRIPE_LP, balanceOfUnderlying); LibUnripe.switchUnderlyingToken(C.UNRIPE_LP, C.BEAN_ETH_WELL); + + // Reset variable to 0 because it wasn't in BIP-36. + delete s.season.withdrawSeasons; } } \ No newline at end of file From 2fd5f8fa72c8f4a4dbaa30b384fc62b72577c400 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:09:18 -0400 Subject: [PATCH 81/96] update comments --- .../contracts/libraries/Oracle/LibEthUsdOracle.sol | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/protocol/contracts/libraries/Oracle/LibEthUsdOracle.sol b/protocol/contracts/libraries/Oracle/LibEthUsdOracle.sol index 1ffd3e3b21..5336fd4aaf 100644 --- a/protocol/contracts/libraries/Oracle/LibEthUsdOracle.sol +++ b/protocol/contracts/libraries/Oracle/LibEthUsdOracle.sol @@ -13,19 +13,19 @@ import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; * @title Eth Usd Oracle Library * @notice Contains functionalty to fetch a manipulation resistant ETH/USD price. * @dev - * The Oracle uses a greey approach to return the average price between the + * The Oracle uses a greedy approach to return the average price between the * current price returned ETH/USD Chainlink Oracle and either the ETH/USDC - * Uniswap V3 0.3 fee pool and the ETH/USDT Uniswap V3 0.3 fee pool depending + * Uniswap V3 0.05% fee pool and the ETH/USDT Uniswap V3 0.05% fee pool depending * on which is closer. - + * + * If the prices in the ETH/USDC Uniswap V3 0.05% fee pool and USD/USDT Uniswap V3 0.05% fee pool are + * greater than `MAX_DIFFERENCE` apart, then the oracle uses the Chainlink price to maximize liveness. + * * The approach is greedy as if the ETH/USDC Uniswap price is sufficiently close * to the Chainlink Oracle price (See {MAX_GREEDY_DIFFERENCE}), then the Oracle * will not check the ETH/USDT Uniswap Price to save gas. * - * There are several conditions that will cause the oracle to fail: - * 1. If the price in both Uniswap pools deviate from the Chainlink price - * by a sufficiently large percent (See {MAX_DIFFERENCE}). - * 2. If the Chainlink Oracle is broken or frozen (See: {LibChainlinkOracle}). + * The oracle will fail if the Chainlink Oracle is broken or frozen (See: {LibChainlinkOracle}). **/ library LibEthUsdOracle { From b4ab34edb9805b7a5d04085c8883384fbe4166cd Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:22:32 -0400 Subject: [PATCH 82/96] remove seeds reference from InitBipBasinIntegration --- .../beanstalk/init/InitBipBasinIntegration.sol | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol b/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol index b03ab87918..ef3bca005f 100644 --- a/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol +++ b/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol @@ -28,8 +28,8 @@ contract InitBipBasinIntegration { AppStorage internal s; - uint32 constant private NEW_BEAN_SEEDS_PER_BDV = 3e6; - uint32 constant private NEW_BEAN_3CRV_SEEDS_PER_BDV = 3.25e6; + uint32 constant private NEW_BEAN_GROWN_STALK_PER_BDV_PER_SEASON = 3e6; + uint32 constant private NEW_BEAN_3CRV_GROWN_STALK_PER_BDV_PER_SEASON = 3.25e6; uint32 constant private BEAN_ETH_SEEDS_PER_BDV = 4.5e6; uint32 constant private STALK_ISSUED_PER_BDV = 10000; @@ -38,8 +38,11 @@ contract InitBipBasinIntegration { function init() external { LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); - LibWhitelist.updateStalkPerBdvPerSeasonForToken(C.BEAN, NEW_BEAN_SEEDS_PER_BDV); - LibWhitelist.updateStalkPerBdvPerSeasonForToken(C.CURVE_BEAN_METAPOOL, NEW_BEAN_3CRV_SEEDS_PER_BDV); + LibWhitelist.updateStalkPerBdvPerSeasonForToken(C.BEAN, NEW_BEAN_GROWN_STALK_PER_BDV_PER_SEASON); + LibWhitelist.updateStalkPerBdvPerSeasonForToken( + C.CURVE_BEAN_METAPOOL, + NEW_BEAN_3CRV_GROWN_STALK_PER_BDV_PER_SEASON + ); LibWhitelist.whitelistToken( C.BEAN_ETH_WELL, IBDVFacet.wellBdv.selector, From fb9cc3da46dae9738d0276f426a3f94918683fc2 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:23:21 -0400 Subject: [PATCH 83/96] update file name --- protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol b/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol index ef3bca005f..f24252b389 100644 --- a/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol +++ b/protocol/contracts/beanstalk/init/InitBipBasinIntegration.sol @@ -14,7 +14,7 @@ import {LibDiamond} from "contracts/libraries/LibDiamond.sol"; /** * @author Publius - * @title InitBipWellsIntegration runs the code for the Basin Integration + * @title InitBipBasinIntegration runs the code for the Basin Integration **/ interface IBDVFacet { From 75fb041241f8f8c3d1e33d1f49c8407a745b6db7 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:25:44 -0400 Subject: [PATCH 84/96] remove unnecssary conditional --- protocol/contracts/ecosystem/price/WellPrice.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/protocol/contracts/ecosystem/price/WellPrice.sol b/protocol/contracts/ecosystem/price/WellPrice.sol index 9f923199b4..8ca79300e4 100644 --- a/protocol/contracts/ecosystem/price/WellPrice.sol +++ b/protocol/contracts/ecosystem/price/WellPrice.sol @@ -61,9 +61,6 @@ contract WellPrice { well.getSwapOut(wellTokens[beanIndex], wellTokens[tknIndex], 1e6) .mul(PRICE_PRECISION) .div(assetPrice); - } else { - // cannnot determine a price for bean if the other asset that bean is trading against is 0. - pool.price = 0; } // liquidity is calculated by getting the usd value of the bean portion of the pool, From 9dc6d4b2cd81a6732c5afcbce74330cd8cc70cfa Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:28:12 -0400 Subject: [PATCH 85/96] add safe cast --- protocol/contracts/ecosystem/price/WellPrice.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/protocol/contracts/ecosystem/price/WellPrice.sol b/protocol/contracts/ecosystem/price/WellPrice.sol index 8ca79300e4..a263e37c0a 100644 --- a/protocol/contracts/ecosystem/price/WellPrice.sol +++ b/protocol/contracts/ecosystem/price/WellPrice.sol @@ -4,6 +4,7 @@ pragma experimental ABIEncoderV2; import {P} from "./P.sol"; import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol"; import {Call, IWell, IERC20} from "../../interfaces/basin/IWell.sol"; import {IBeanstalkWellFunction} from "../../interfaces/basin/IBeanstalkWellFunction.sol"; import {LibUsdOracle} from "../../libraries/Oracle/LibUsdOracle.sol"; @@ -24,6 +25,7 @@ interface dec{ contract WellPrice { using SafeMath for uint256; + using SafeCast for uint256; IBeanstalk private constant BEANSTALK = IBeanstalk(0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5); uint256 private constant WELL_DECIMALS = 1e18; @@ -91,7 +93,7 @@ contract WellPrice { wellFunction.data ); - deltaB = int256(beansAtPeg) - int256(reserves[beanIndex]); + deltaB = beansAtPeg.toInt256() - reserves[beanIndex].toInt256(); } } From 6b976ce6f746fd13309190af3f4cb32cc5c91d5c Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:29:57 -0400 Subject: [PATCH 86/96] fix natspec typo --- protocol/contracts/beanstalk/barn/FertilizerFacet.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index 2a7ab72161..ea10921669 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -105,7 +105,7 @@ contract FertilizerFacet { } /** - * @dev Returns the amount of Fertilize that can be purchased with `wethAmountIn` WETH. + * @dev Returns the amount of Fertilizer that can be purchased with `wethAmountIn` WETH. * Can be used to help calculate `minFertilizerOut` in `mintFertilizer`. * `wethAmountIn` has 18 decimals, `getEthUsdPrice()` has 6 decimals and `fertilizerAmountOut` has 0 decimals. */ From 883e6e19d17c74fa0b68c0b9aca33bf03c031852 Mon Sep 17 00:00:00 2001 From: brendan Date: Fri, 22 Sep 2023 15:30:44 -0400 Subject: [PATCH 87/96] update natspec comment in _mow --- protocol/contracts/libraries/Silo/LibSilo.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/contracts/libraries/Silo/LibSilo.sol b/protocol/contracts/libraries/Silo/LibSilo.sol index 79c6046abf..e5629586b3 100644 --- a/protocol/contracts/libraries/Silo/LibSilo.sol +++ b/protocol/contracts/libraries/Silo/LibSilo.sol @@ -349,7 +349,7 @@ library LibSilo { AppStorage storage s = LibAppStorage.diamondStorage(); //sop stuff only needs to be updated once per season - //if it started raininga nd it's still raining, or there was a sop + //if it started raining and it's still raining, or there was a sop if (s.season.rainStart > s.season.stemStartSeason) { uint32 lastUpdate = _lastUpdate(account); if (lastUpdate <= s.season.rainStart && lastUpdate <= s.season.current) { From 9f91f9612c31b843291198b28ef36226468f9582 Mon Sep 17 00:00:00 2001 From: Brean0 Date: Mon, 25 Sep 2023 17:04:41 +0900 Subject: [PATCH 88/96] update sciNotation comment --- protocol/contracts/beanstalk/metadata/MetadataImage.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/contracts/beanstalk/metadata/MetadataImage.sol b/protocol/contracts/beanstalk/metadata/MetadataImage.sol index 8e7989c67f..459c70bd76 100644 --- a/protocol/contracts/beanstalk/metadata/MetadataImage.sol +++ b/protocol/contracts/beanstalk/metadata/MetadataImage.sol @@ -533,14 +533,14 @@ contract MetadataImage { function sciNotation(int96 stem) internal pure returns (string memory) { if (stem >= 0) { - // if stem is greater than 1e7, use scientific notation + // if stem is greater than 1e5, use scientific notation if (stem > 100_000) { return powerOfTen(uint256(stem)); } else { return uint256(stem).toString(); } } else { - // if stem is greater than 1e7, use scientific notation + // if stem is less than -1e5, use scientific notation if (-stem > 100_000) { return string(abi.encodePacked("-", powerOfTen(uint256(-stem)))); } else { From 615ba1c32c6a14db53563efaff9cbe437aef952d Mon Sep 17 00:00:00 2001 From: Brean0 Date: Mon, 25 Sep 2023 18:57:11 +0900 Subject: [PATCH 89/96] added proper testnet mocks for quicker metadata testing. - additionally, changed generate image from `view` to `pure`. --- .../beanstalk/metadata/MetadataImage.sol | 2 +- .../contracts/mocks/MockMetadataERC1155.sol | 51 +++++++++++ .../contracts/mocks/MockMetadataFacet.sol | 85 +++++++++++++++++++ protocol/hardhat.config.js | 1 + protocol/scripts/deployMockMetadata.js | 25 ++++++ 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 protocol/contracts/mocks/MockMetadataERC1155.sol create mode 100644 protocol/contracts/mocks/MockMetadataFacet.sol create mode 100644 protocol/scripts/deployMockMetadata.js diff --git a/protocol/contracts/beanstalk/metadata/MetadataImage.sol b/protocol/contracts/beanstalk/metadata/MetadataImage.sol index 459c70bd76..b22edf6a2a 100644 --- a/protocol/contracts/beanstalk/metadata/MetadataImage.sol +++ b/protocol/contracts/beanstalk/metadata/MetadataImage.sol @@ -36,7 +36,7 @@ contract MetadataImage { ); } - function generateImage(address token, int96 stem, int96 stemTip) internal view returns (string memory) { + function generateImage(address token, int96 stem, int96 stemTip) internal pure returns (string memory) { int96 grownStalkPerBdv = stemTip - stem; return string( abi.encodePacked( diff --git a/protocol/contracts/mocks/MockMetadataERC1155.sol b/protocol/contracts/mocks/MockMetadataERC1155.sol new file mode 100644 index 0000000000..ffbb3e08e7 --- /dev/null +++ b/protocol/contracts/mocks/MockMetadataERC1155.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.7.6; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; + +/** + * @author brean + * @dev used to deploy on testnets to verify that json data and SVG encoding is correct. + * Steps for testing: + * 1: deploy MockMetadataFacet + * 2: deploy MetadataMockERC1155 with the address of the MockMetadataFacet. + * (MockMetadataFacet with ERC1155 exceeds the contract size limit.) +**/ + +interface IMetadataFacet { + function uri(uint256 depositId) external view returns (string memory); + + function name() external pure returns (string memory); + + function symbol() external pure returns (string memory); +} + +contract MockMetadataERC1155 is ERC1155 { + + address public mockMetadataFacetaddress; + + constructor (string memory name, address metadataAddress) ERC1155(name) { + mockMetadataFacetaddress = metadataAddress; + } + + function mockMint(address account, uint256 id, uint256 amount) external { + _mint(account, id, amount, new bytes(0)); + } + + function changeMetadataFacet(address metadataAddress) external { + mockMetadataFacetaddress = metadataAddress; + } + + function uri(uint256 depositId) external override view returns (string memory) { + return IMetadataFacet(mockMetadataFacetaddress).uri(depositId); + } + + function name() external view returns (string memory){ + return IMetadataFacet(mockMetadataFacetaddress).name(); + } + + function symbol() external view returns (string memory){ + return IMetadataFacet(mockMetadataFacetaddress).symbol(); + } +} \ No newline at end of file diff --git a/protocol/contracts/mocks/MockMetadataFacet.sol b/protocol/contracts/mocks/MockMetadataFacet.sol new file mode 100644 index 0000000000..b58b1f3f5f --- /dev/null +++ b/protocol/contracts/mocks/MockMetadataFacet.sol @@ -0,0 +1,85 @@ +/* + SPDX-License-Identifier: MIT +*/ + +pragma solidity =0.7.6; +pragma experimental ABIEncoderV2; + +import "contracts/beanstalk/metadata/MetadataImage.sol"; +import {LibBytes} from "contracts/libraries/LibBytes.sol"; +import {LibTokenSilo} from "contracts/libraries/Silo/LibTokenSilo.sol"; +import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; + +/** + * @author brean + * @title MockMetadataFacet is a Mock version of MetadataFacet. + * @dev used to deploy on testnets to verify that json data and SVG encoding is correct. + * Steps for testing: + * 1: deploy MockMetadataFacet + * 2: deploy MetadataMockERC1155 with the address of the MockMetadataFacet. + * (MockMetadataFacet with ERC1155 exceeds the contract size limit.) +**/ +contract MockMetadataFacet is MetadataImage { + using SafeMath for uint256; + + // inital conditions: 2 seeds, 1000 seasons has elapsed from milestone season. + uint256 public stalkEarnedPerSeason = 2e6; + uint256 public seasonsElapsed = 1000; + uint256 public stalkIssuedPerBdv = 10000; + + using LibStrings for uint256; + using LibStrings for int256; + + event URI(string _uri, uint256 indexed _id); + + /** + * @notice Returns the URI for a given depositId. + * @param depositId - the id of the deposit + * @dev the URI is a base64 encoded JSON object that contains the metadata and base64 encoded svg. + * Deposits are stored as a mapping of a uint256 to a Deposit struct. + * ERC20 deposits are represented by the concatination of the token address and the stem. (20 + 12 bytes). + */ + function uri(uint256 depositId) external view returns (string memory) { + (address token, int96 stem) = LibBytes.unpackAddressAndStem(depositId); + int96 stemTip = int96(stalkEarnedPerSeason.mul(seasonsElapsed)); + bytes memory attributes = abi.encodePacked( + '\\n\\nToken Symbol: ', getTokenName(token), + '\\nToken Address: ', LibStrings.toHexString(uint256(token), 20), + '\\nId: ', depositId.toHexString(32), + '\\nstem: ', int256(stem).toString(), + '\\ninital stalk per BDV: ', stalkIssuedPerBdv.toString(), + '\\ngrown stalk per BDV: ', uint256(stemTip - stem).toString(), + '\\nstalk grown per BDV per season: ', stalkEarnedPerSeason.toString(), + '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."' + ); + return string(abi.encodePacked("data:application/json;base64,",LibBytes64.encode(abi.encodePacked( + '{', + '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage.', + attributes, + string(abi.encodePacked(', "image": "', imageURI(token, stem, stemTip), '"')), + '}' + )) + )); + } + + function name() external pure returns (string memory){ + return "Beanstalk Silo Deposits"; + } + + function symbol() external pure returns (string memory){ + return "DEPOSIT"; + } + + function setSeeds(uint256 _stalkEarnedPerSeason) external { + stalkEarnedPerSeason = _stalkEarnedPerSeason; + } + + function setSeasonElapsed(uint256 _seasonsElapsed) external { + seasonsElapsed = _seasonsElapsed; + } + + function setStalkIssuedPerBdv(uint256 _stalkIssuedPerBdv) external { + stalkIssuedPerBdv = _stalkIssuedPerBdv; + } + +} diff --git a/protocol/hardhat.config.js b/protocol/hardhat.config.js index 5aa013e896..25c47db484 100644 --- a/protocol/hardhat.config.js +++ b/protocol/hardhat.config.js @@ -263,6 +263,7 @@ module.exports = { goerli: { chainId: 5, url: process.env.GOERLI_RPC || "", + accounts: [process.env.GOERLI_PRIVATE_KEY], timeout: 100000 } }, diff --git a/protocol/scripts/deployMockMetadata.js b/protocol/scripts/deployMockMetadata.js new file mode 100644 index 0000000000..f07030360c --- /dev/null +++ b/protocol/scripts/deployMockMetadata.js @@ -0,0 +1,25 @@ +const hre = require("hardhat"); + + +async function main() { + const MockMetadataFacet = await ethers.getContractFactory('MockMetadataFacet'); + console.log('Deploying MockMetadataFacet...'); + const mockMetadataFacet = await MockMetadataFacet.deploy(); + await mockMetadataFacet.deployed(); + console.log('mockMetadataFacet deployed to:', mockMetadataFacet.address); + + // only needs to be deployed once. Deploy a new mockMetdata facet, then change the address on MockMetadataERC1155. + const MockMetadataERC1155 = await ethers.getContractFactory('MockMetadataERC1155'); + console.log('Deploying MockMetadataERC1155...'); + const mockMetadataERC1155 = await MockMetadataERC1155.deploy('TEST', '0xE40036Db7c1E5f366153B16a2c249EB2bf04bCcc'); + await mockMetadataERC1155.deployed(); + console.log('metadataMockERC1155 deployed to:', mockMetadataERC1155.address); + + } + + main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); \ No newline at end of file From 1b55b221583bd6737be6d87169164207aec71364 Mon Sep 17 00:00:00 2001 From: brendan Date: Mon, 25 Sep 2023 13:17:17 -0400 Subject: [PATCH 90/96] require > 0 fertilizer bought in mintFertilizer --- protocol/contracts/beanstalk/barn/FertilizerFacet.sol | 3 ++- protocol/test/Fertilizer.test.js | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol index ea10921669..75c02783f9 100644 --- a/protocol/contracts/beanstalk/barn/FertilizerFacet.sol +++ b/protocol/contracts/beanstalk/barn/FertilizerFacet.sol @@ -78,7 +78,8 @@ contract FertilizerFacet { fertilizerAmountOut = getMintFertilizerOut(wethAmountIn); - require(fertilizerAmountOut >= minFertilizerOut, "Fertilizer Not enough bought."); + require(fertilizerAmountOut >= minFertilizerOut, "Fertilizer: Not enough bought."); + require(fertilizerAmountOut > 0, "Fertilizer: None bought."); uint128 remaining = uint128(LibFertilizer.remainingRecapitalization().div(1e6)); // remaining <= 77_000_000 so downcasting is safe. require(fertilizerAmountOut <= remaining, "Fertilizer: Not enough remaining."); diff --git a/protocol/test/Fertilizer.test.js b/protocol/test/Fertilizer.test.js index a7a1df7540..d3ca109422 100644 --- a/protocol/test/Fertilizer.test.js +++ b/protocol/test/Fertilizer.test.js @@ -270,6 +270,11 @@ describe('Fertilize', function () { }) describe("Mint Fertilizer", async function () { + it('Reverts if mints 0', async function () { + await this.season.teleportSunrise('6274') + await expect(this.fertilizer.connect(user).mintFertilizer('0', '0', '0', EXTERNAL)).to.be.revertedWith('Fertilizer: None bought.') + }) + describe('1 mint', async function () { beforeEach(async function () { await this.season.teleportSunrise('6274') From 2f2994bcd677c34d6f0721e4e85e954691d9dc82 Mon Sep 17 00:00:00 2001 From: Brean0 Date: Tue, 26 Sep 2023 16:03:50 +0900 Subject: [PATCH 91/96] update metadata to put values in traits rather than in description. - this allows users of NFT marketplaces to filter NFTs by criteria's. --- .../beanstalk/metadata/MetadataFacet.sol | 18 ++++++++--------- .../contracts/mocks/MockMetadataFacet.sol | 20 +++++++++---------- protocol/scripts/deployMockMetadata.js | 2 +- protocol/test/data/base64EncodedImageBean.txt | 2 +- .../test/data/base64EncodedImageBean3Crv.txt | 2 +- .../test/data/base64EncodedImageBeanEth.txt | 2 +- .../test/data/base64EncodedImageUrBean.txt | 2 +- .../test/data/base64EncodedImageUrBeanEth.txt | 2 +- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/protocol/contracts/beanstalk/metadata/MetadataFacet.sol b/protocol/contracts/beanstalk/metadata/MetadataFacet.sol index 16290a63ba..b4df7233c1 100644 --- a/protocol/contracts/beanstalk/metadata/MetadataFacet.sol +++ b/protocol/contracts/beanstalk/metadata/MetadataFacet.sol @@ -36,18 +36,18 @@ contract MetadataFacet is MetadataImage { int96 stemTip = LibTokenSilo.stemTipForToken(token); require(token != address(0), "Silo: metadata does not exist"); bytes memory attributes = abi.encodePacked( - '\\n\\nToken Symbol: ', getTokenName(token), - '\\nToken Address: ', LibStrings.toHexString(uint256(token), 20), - '\\nId: ', depositId.toHexString(32), - '\\nstem: ', int256(stem).toString(), - '\\ninital stalk per BDV: ', uint256(LibTokenSilo.stalkIssuedPerBdv(token)).toString(), - '\\ngrown stalk per BDV: ', uint256(stemTip - stem).toString(), - '\\nstalk grown per BDV per season: ', uint256(LibTokenSilo.stalkEarnedPerSeason(token)).toString(), - '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."' + ', "attributes": [ { "trait_type": "Token", "value": "', getTokenName(token), + '"}, { "trait_type": "Token Address", "value": "', LibStrings.toHexString(uint256(token), 20), + '"}, { "trait_type": "Id", "value": "', depositId.toHexString(32), + '"}, { "trait_type": "stem", "display_type": "number", "value": ', int256(stem).toString(), + '}, { "trait_type": "inital stalk per BDV", "display_type": "number", "value": ', uint256(LibTokenSilo.stalkIssuedPerBdv(token)).toString(), + '}, { "trait_type": "grown stalk per BDV", "display_type": "number", "value": ', uint256(stemTip - stem).toString(), + '}, { "trait_type": "stalk grown per BDV per season", "display_type": "number", "value": ', uint256(LibTokenSilo.stalkEarnedPerSeason(token)).toString() ); return string(abi.encodePacked("data:application/json;base64,",LibBytes64.encode(abi.encodePacked( '{', - '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage.', + '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage. ', + '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."', attributes, string(abi.encodePacked(', "image": "', imageURI(token, stem, stemTip), '"')), '}' diff --git a/protocol/contracts/mocks/MockMetadataFacet.sol b/protocol/contracts/mocks/MockMetadataFacet.sol index b58b1f3f5f..ad6cc38b1e 100644 --- a/protocol/contracts/mocks/MockMetadataFacet.sol +++ b/protocol/contracts/mocks/MockMetadataFacet.sol @@ -43,20 +43,20 @@ contract MockMetadataFacet is MetadataImage { (address token, int96 stem) = LibBytes.unpackAddressAndStem(depositId); int96 stemTip = int96(stalkEarnedPerSeason.mul(seasonsElapsed)); bytes memory attributes = abi.encodePacked( - '\\n\\nToken Symbol: ', getTokenName(token), - '\\nToken Address: ', LibStrings.toHexString(uint256(token), 20), - '\\nId: ', depositId.toHexString(32), - '\\nstem: ', int256(stem).toString(), - '\\ninital stalk per BDV: ', stalkIssuedPerBdv.toString(), - '\\ngrown stalk per BDV: ', uint256(stemTip - stem).toString(), - '\\nstalk grown per BDV per season: ', stalkEarnedPerSeason.toString(), - '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."' + ', "attributes": [ { "trait_type": "Token", "value": "', getTokenName(token), + '"}, { "trait_type": "Token Address", "value": "', LibStrings.toHexString(uint256(token), 20), + '"}, { "trait_type": "Id", "value": "', depositId.toHexString(32), + '"}, { "trait_type": "stem", "display_type": "number", "value": ', int256(stem).toString(), + '}, { "trait_type": "inital stalk per BDV", "display_type": "number", "value": ', stalkIssuedPerBdv.toString(), + '}, { "trait_type": "grown stalk per BDV", "display_type": "number", "value": ', uint256(stemTip - stem).toString(), + '}, { "trait_type": "stalk grown per BDV per season", "display_type": "number", "value": ', stalkEarnedPerSeason.toString() ); return string(abi.encodePacked("data:application/json;base64,",LibBytes64.encode(abi.encodePacked( '{', - '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage.', + '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage. ', + '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."', attributes, - string(abi.encodePacked(', "image": "', imageURI(token, stem, stemTip), '"')), + string(abi.encodePacked('}], "image": "', imageURI(token, stem, stemTip), '"')), '}' )) )); diff --git a/protocol/scripts/deployMockMetadata.js b/protocol/scripts/deployMockMetadata.js index f07030360c..5d8845977f 100644 --- a/protocol/scripts/deployMockMetadata.js +++ b/protocol/scripts/deployMockMetadata.js @@ -11,7 +11,7 @@ async function main() { // only needs to be deployed once. Deploy a new mockMetdata facet, then change the address on MockMetadataERC1155. const MockMetadataERC1155 = await ethers.getContractFactory('MockMetadataERC1155'); console.log('Deploying MockMetadataERC1155...'); - const mockMetadataERC1155 = await MockMetadataERC1155.deploy('TEST', '0xE40036Db7c1E5f366153B16a2c249EB2bf04bCcc'); + const mockMetadataERC1155 = await MockMetadataERC1155.deploy('TEST', '0x12a5c6fdF938F276bdf67961a9cc0B58092eDAC9'); await mockMetadataERC1155.deployed(); console.log('metadataMockERC1155 deployed to:', mockMetadataERC1155.address); diff --git a/protocol/test/data/base64EncodedImageBean.txt b/protocol/test/data/base64EncodedImageBean.txt index 4ff6e6acf8..bb4bdcdbdb 100644 --- a/protocol/test/data/base64EncodedImageBean.txt +++ b/protocol/test/data/base64EncodedImageBean.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IEJFQU5cblRva2VuIEFkZHJlc3M6IDB4YmVhMDAwMDAyOWFkMWM3N2QzZDVkMjNiYTJkODg5M2RiOWQxZWZhYlxuSWQ6IDB4YmVhMDAwMDAyOWFkMWM3N2QzZDVkMjNiYTJkODg5M2RiOWQxZWZhYjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMlxuc3RlbTogMlxuaW5pdGFsIHN0YWxrIHBlciBCRFY6IDEwMDAwXG5ncm93biBzdGFsayBwZXIgQkRWOiAyMDAwXG5zdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb246IDIwMDAwMDBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCamJHRnpjejBpYzNablFtOWtlU0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJek5UQWlJSFpwWlhkQ2IzZzlJakFnTUNBeU5UVWdNelV3SWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhodGJHNXpPbmhzYVc1clBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJajQ4WkdWbWN6NDhaeUJwWkQwaWNHeHZkQ0krUEhCaGRHZ2daRDBpVFRjNUxqVTNNamdnTVRJNUxqSTJOVXd4TWpjdU5EWTVJREUxTmk0NE16Tk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UQXhMalk1TjB3M09TNDFOekk0SURFeU9TNHlOalZhSWlCbWFXeHNQU0lqT1RRMFFUSTNJaTgrUEhCaGRHZ2daRDBpVFRjNUxqVXpNeklnTVRNekxqUXlOa3czT1M0MU56STNJREV5T1M0eU5qVk1NVEkzTGpRMk9TQXhOVFl1T0RNelRERXlOeTQxTURjZ01UWXdMamt3T0V3M09TNDFNek15SURFek15NDBNalphSWlCbWFXeHNQU0lqTnpVek9URkdJaTgrUEhCaGRHZ2daRDBpVFRFM05TNDBOamNnTVRNekxqUk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UVTJMamd6TTB3eE1qY3VOVEEzSURFMk1DNDVNRGhNTVRjMUxqUTJOeUF4TXpNdU5Gb2lJR1pwYkd3OUlpTTJOek16TVVVaUx6NDhMMmMrUEdjZ2FXUTlJbVoxYkd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUWXdJaUI1UFNJeE5DSWdabWxzYkQwaUkwRTRRemd6UVNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUY3pJaUI1UFNJeU1TSWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKbGJYQjBlVkJzYjNRaVBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQnNiM1FpSUhnOUlpMHpOU0lnZVQwaU1DSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSndZWEowYVdGc1RHVmhabEp2ZHlJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaU1DSWdlVDBpTUNJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1lpSUhnOUlpMHhNaUlnZVQwaUxUY2lMejQ4TDJjK1BHY2dhV1E5SW5CaGNuUnBZV3hNWldGbVVHeHZkQ0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0d4dmRDSWdlRDBpTFRNMUlpQjVQU0l3SWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5zWldGbVVtOTNJaUI0UFNJdE16VWlJSGs5SWpBaUlHWnBiR3c5SWlOQk9FTTRNMEVpSUhSeVlXNXpabTl5YlQwaWMyTmhiR1VvTVM0MEtTSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdaU2IzY2lJSGc5SWkwME55SWdlVDBpTnlJZ1ptbHNiRDBpSXpnNVFUWXlSaUlnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR0Z5ZEdsaGJFeGxZV1pTYjNjaUlIZzlJaTAyTUNJZ2VUMGlNVFFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmlJK1BIQmhkR2dnWkQwaVRURTNNUzQ0T0RRZ01URTRMams0TTJFMExqa3pNaUEwTGprek1pQXdJREFnTVMweExqQXhPQ0F5TGpZd05pQTBMamN4TlNBMExqY3hOU0F3SURBZ01TMHhMamczT0NBeExqUXpPV010TGpRMk5TNHhPVFV0TVM0M016VXVOekkzTFRJdU16WTBMakUzTmkwdU1qUTJJRE11TWprNExURXVOVGt6SURZdU5URXlMVEl1TWpVeklEY3VPVFUwWVRRdU5UTXlJRFF1TlRNeUlEQWdNQ0F4TFM0ek1UTXRMamt6TTJNdExqSXhNUzB1T1RjMUxTNHdNemd0TVM0M05qTXVNRGM0TFRJdU1qazFMakl3TWkwdU9USXhMak0xTXkweExqWXhNaTQwTmpjdE1pNHhOQzB4TGpFM055NDJPVFF0TWk0Mk5ESXVOVFk1TFRNdU5UVTRMUzR5TnpJdExqYzVOaTB1TnpNeUxURXVNRGd6TFRFdU9USXhMUzQzTkRNdE15NHdNelF1TkRrNExqQXhNU0F4TGprek9TNHhNRGtnTXk0eU5EY2dNUzR4TmpkaE5TNHhNeUExTGpFeklEQWdNQ0F4SURFdU1qRWdNUzQwTVROakxqRTFPUzB1TnpRdU1UazVMUzQ1TlRndU1qTTRMVEV1TVRjNUxqSXdPUzB4TGpJeE15NHpNakl0TVM0NE56SXVNamMwTFRJdU56STBZVGN1TnpNZ055NDNNeUF3SURBZ01DMHVPVEE0TFRNdU1UYzNZeTB1TnpjeUxqUXhOUzB4TGpjNE9TNHhPVFl0TWk0ek56Z3RMak13TkMwdU16TTVMUzR5T0RjdExqVTFOaTB1TmpneUxTNDNOalF0TVM0Mk9USmhNVEl1TnpNNUlERXlMamN6T1NBd0lEQWdNUzB1TVRjMkxUTXVPVEE1WXk0M09Ea3VOakF6SURFdU5EY2dNUzR3TVRrZ01TNDVNemNnTVM0eU9ETXVPVFEwTGpVek5pQXhMak0wTkM0Mk16a2dNUzQzTmpFZ01TNHhOamN1TVRVeUxqRTVNeTQyTkRrdU9EUXlMalU0TmlBeExqYzFNUzB1TURFeExqRTNNaTB1TURVekxqYzVOUzB1TkRZMElERXVNamt6WVRZdU9ETWdOaTQ0TXlBd0lEQWdNU0F4TGpNNE5DQXlMakl5TjJNdU1UUXVNelk0TGpJME1pNDNORFF1TXpFeElERXVNVFV1TVRBM0xTNHlNRGN1TWpZeExTNDBNemt1TlRFeExTNDNNakl1TkRVekxTNDFNVE11T0RjdExqazVNaUF4TGpZd05DMHhMakk0TkM0Mk9ETXRMakkzTWlBeExqSTRMUzR5TkRrZ01TNDNNak10TGpJek5HRTFMak13TWlBMUxqTXdNaUF3SURBZ01TQXhMalE0Tmk0eU56TmFJaTgrUEM5blBqeG5JR2xrUFNKemFXeHZJajQ4Y0dGMGFDQmtQU0pOTlRjdU1UQTRJRGN4TGpJNVl5NHhPRGd0TVRFdU5qVXpMVEV5TGpBeExUSXhMak13TXkweU55NHlORE10TWpFdU5UVXlMVEUxTGpJek5DMHVNalV0TWpjdU56TTJJRGd1T1RrMUxUSTNMamt5TXlBeU1DNDJORGt0TGpFNE55QXhNUzQyTlRRZ01USXVNREVnTWpFdU16QTBJREkzTGpJME5DQXlNUzQxTlRNZ01UVXVNak16TGpJMUlESTNMamN6TlMwNExqazVOU0F5Tnk0NU1qSXRNakF1TmpWYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFM0ME5qUWdNVGt1TlRRMFl5NDJPVGtnTVRZdU5UZzFJREV1TkNBek15NHhOamtnTWk0d09UZ2dORGt1TnpVeUxqQXlNU0F5TGpNNE1TNDBPQ0EwTGpJM09DNDRPRE1nTlM0MU16a3VNamMzTGpnMkxqYzBNU0F5TGpJM05TQXhMamMzT0NBekxqZzJOeTQwT1RRdU56VTVJREV1TWpFeUlERXVOeUF6TGpBd01pQXpMak16TWlBeExqY3pPU0F4TGpVNE5pQXpMak0xSURNdU1EVTJJRFV1TnpNeUlEUXVNems0SURNdU1qa3pJREV1T0RVMUlEWXVNVFV4SURJdU16azJJRGd1TnpreElESXVPRGsySURFdU9EVTFMak0xSURVdU1UUTVMamswT0NBNUxqUTRPQzQxTlRaaE16SXVOekEzSURNeUxqY3dOeUF3SURBZ01DQTVMak14TlMweUxqSTROMk14TGpnMk1pMHVOelU1SURRdU5qUXlMVEV1T1RFM0lEY3VOak16TFRRdU5DQXhMak0wT0MweExqRXlJRE11TkRRNExUSXVPRGszSURVdU1UazNMVFV1T1RWaE1qQXVNVEUwSURJd0xqRXhOQ0F3SURBZ01DQXlMakkxTFRVdU9UazRZeTR5TVMweE55NDFOVEl1TkRJdE16VXVNVEEwTGpZek1pMDFNaTQyTlRkc0xUVTJMamd1T1RVeWFDNHdNREZhSWlCbWFXeHNQU0lqUWpOQ00wSXpJaTgrUEhCaGRHZ2daRDBpVFRVM0xqUTRJREU1TGpRNE1rTTFOeTQyTkRVZ09TNHlOQ0EwTkM0NU56Z3VOekkzSURJNUxqRTROeTQwTmpnZ01UTXVNemszTGpJeExqUTJNeUE0TGpNd015NHlPVGdnTVRndU5UUTJMakV6TkNBeU9DNDNPRGdnTVRJdU9DQXpOeTR6SURJNExqVTVNU0F6Tnk0MU5tTXhOUzQzT1M0eU5UZ2dNamd1TnpJMExUY3VPRE0xSURJNExqZzRPUzB4T0M0d056aGFJaUJtYVd4c1BTSWpRME5ESWk4K1BIQmhkR2dnWkQwaVRUTXdMak14TkNBM0xqRXpOMk11TURBNUxTNDFOakV0TGpZNExURXVNREk0TFRFdU5UTTRMVEV1TURReUxTNDROVGt0TGpBeE5DMHhMalUyTWk0ME15MHhMalUzTVM0NU9URXRMakF4TGpVMk1pNDJPQ0F4TGpBeU9DQXhMalV6T0NBeExqQTBNaTQ0TlRrdU1ERTFJREV1TlRZeUxTNDBNeUF4TGpVM0xTNDVPVm9pSUdacGJHdzlJaU0yTmpZaUx6NDhjR0YwYUNCa1BTSk5OaTQwTVRRZ01qZ3VPRGxoTVRVdU56YzNJREUxTGpjM055QXdJREFnTVMweUxqQTVNeTB5TGpFME5tTXRMamcxTmkweExqQTJNeTB5TGpRMU15MHpMakE1TXkweUxqazNOUzAyTGpFeE1tRXhNUzQzTmpVZ01URXVOelkxSURBZ01DQXhMUzR3T1RNdE15NHpNRGRzTWpVdU5ETXRPUzQ1TnpaakxqQTBNeTR4TkRJdU1UZzRMalUxTlM0Mk1EUXVPRFk0TGpRMkxqTTBOaTQ1TkRjdU16UWdNUzR3T0RZdU16TTBURFl1TkRFeklESTRMamc0T0hZdU1EQXlXaUlnWm1sc2JEMGlJMFUyUlRaRk5pSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNHpNeUlnWkQwaVRURXVORGMzSURFMkxqQXlPV011TWpVdExqa3pNUzQzTURZdE1pNHlOVGdnTVM0MU55MHpMalk1TlM0Mk5UVXRNUzR3T1RJZ01TNHlPVEl0TVM0NE1qVWdNUzQzTmkweUxqTTFPQzQxT0RRdExqWTJOU0F4TGpjM05pMHhMamt6TkNBekxqWTNPUzB6TGpJNUlESXVPVFV6TFRJdU1UQTFJRFV1TmprMkxUTXVNRFVnTnk0M01qTXRNeTQzTTJFek55NHpOU0F6Tnk0ek5TQXdJREFnTVNBMkxqUTROUzB4TGpVME4ydzFMakkwTWlBMExqTXhObUV4TGpRNElERXVORGdnTUNBd0lEQXRNUzR5TVRRdU9UWTNUREV1TkRnZ01UWXVNRE5vTFM0d01ESmFJaUJtYVd4c1BTSWpPVGs1SWk4K1BIQmhkR2dnYjNCaFkybDBlVDBpTGpRMElpQmtQU0pOTVM0NE1TQXlOaTQxTXpKakxqSXdOaTQwT1RRdU5EZzBJREV1TURVdU9EWWdNUzQyTTJFeE1DNHlOallnTVRBdU1qWTJJREFnTUNBd0lESXVNamM0SURJdU5EZzJURFl1TlRVeUlEYzRMakl5WVRFM0xqSTNNaUF4Tnk0eU56SWdNQ0F3SURFdE15MDNMalF4TTB3eExqZ3hJREkyTGpVek1sb2lJR1pwYkd3OUlpTkZOa1UyUlRZaUx6NDhjR0YwYUNCa1BTSnRNek11TURreUlEUTVMalEwTVMwMkxqTTRNU0F4TlM0eU1URnpMVFl1TURjNExURXhMakUxT1NBMkxqTTRNUzB4TlM0eU1Wb2lJR1pwYkd3OUlpTTRSVGhGT0VVaUx6NDhjR0YwYUNCa1BTSnRNall1TnpJMUlEWTBMamcxT0MwdU1Ea3hMUzR4TnpWakxTNHdNall0TGpBME9TMHlMall6TkMwMExqa3lNeTB1T0RZM0xUa3VNemNnTVM0d05UY3RNaTQzTVRjZ015NDFNVGd0TkM0M01qVWdOeTR6TFRVdU9UUTJiQzR4T0RjdExqQTJNUzAyTGpVeklERTFMalUxTWxwdE5pNHlNVEl0TVRVdU1qWTRZeTB6TGpZeU1TQXhMakl4TnkwMUxqazVNU0F6TGpFMk9DMDNMakF5TWlBMUxqYzVPQzB4TGpVek9DQXpMamt3T0M0ek5UVWdPQzR4TmpZdU56ZzRJRGt1TURVMGJEWXVNak0wTFRFMExqZzFNbHBOTWpndU1Ea3pJRFl6TGpjek4ydzBMalE0TkMweE1DNDROM00zTGpNMk5TQTJMak16TnkwMExqUTROQ0F4TUM0NE4xb2lJR1pwYkd3OUlpTTRSVGhGT0VVaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNME5rSTVOVFVpTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGpORFVsWWlQanh5WldOMElIazlJaTQxSWlCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU56WTBMVE11TlRBMElEa3VNelpUTGpJNU9DQTBMalE1T1NBM0xqWTROeUF4TGpjMk5Wb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNHhNeklnT0M0d056aGpMUzQwTmpZdU5qUXRNUzR5T1RjZ01TNHpNak10TWk0Mk9UVWdNUzQ1T1RKc01pNHhNall0TlM0M056ZGpMakE0T1M0d09TNHhPVE11TWpBMExqTXVNek00TGpNd015NHpOelV1TmpJMUxqZzVNUzQzTkRRZ01TNDBPRFF1TVRFM0xqVTRNeTR3TkNBeExqSTFNeTB1TkRjMUlERXVPVFl6V2lJZ1ptbHNiRDBpZFhKc0tDTmhLU0lnYzNSeWIydGxQU0lqWm1abUlpQnpkSEp2YTJVdGQybGtkR2c5SWk0MUlpOCtQR1JsWm5NK1BHeHBibVZoY2tkeVlXUnBaVzUwSUdsa1BTSmhJaUI0TVQwaU5pNDVOU0lnZVRFOUlqTXVPRFV6SWlCNE1qMGlOaTQ1TlNJZ2VUSTlJakV3TGpVME5DSWdaM0poWkdsbGJuUlZibWwwY3owaWRYTmxjbE53WVdObFQyNVZjMlVpUGp4emRHOXdJSE4wYjNBdFkyOXNiM0k5SWlNNE1qQXlNRElpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJaTR4T0RJaUlITjBiM0F0WTI5c2IzSTlJaU5HTnpGRk1EVWlMejQ4YzNSdmNDQnZabVp6WlhROUlpNDFNVFlpSUhOMGIzQXRZMjlzYjNJOUlpTkdNRVkxTURjaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWk0M016UWlJSE4wYjNBdFkyOXNiM0k5SWlNNE5VTkVOelVpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJakVpSUhOMGIzQXRZMjlzYjNJOUlpTXdNamxFUmtJaUx6NDhMMnhwYm1WaGNrZHlZV1JwWlc1MFBqd3ZaR1ZtY3o0OEwyYytQR2NnYVdROUluVnlRa1ZCVGlJK1BISmxZM1FnZDJsa2RHZzlJakV5SWlCb1pXbG5hSFE5SWpFeUlpQnllRDBpTmlJZ1ptbHNiRDBpSXpkR05UVXpNeUl2UGp4d1lYUm9JR1E5SW0wM0xqWTROeUF4TGpJMk5TMHpMalV3TkNBNUxqTTJVeTR5T1RnZ015NDVPVGtnTnk0Mk9EY2dNUzR5TmpaYWJTMHlMalk1TVNBNExqYzRJREl1TkRZeUxUWXVOamt4Y3pRdU5UTTRJRE11TmpjdE1pNDBOaklnTmk0Mk9URmFJaUJtYVd4c1BTSWpabVptSWk4K1BDOW5QanhuSUdsa1BTSkNSVUZPUlZSSUlqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamcwSURFdU1qWTFMVE11TlRBMUlEa3VNelpqTGpBd015QXdMVE11T0RnMExUWXVOakkxSURNdU5UQTFMVGt1TXpaYUlpQm1hV3hzUFNJalptWm1JaTgrUEhCaGRHZ2daRDBpVFRndU9UVXlJRFl1T1RnMllTNHdOak11TURZeklEQWdNQ0F4TFM0d01qSXVNREF6WXkwdU56RXVNVE10TVM0ME1qUXVNalUxTFRJdU1UTTBMak00TVMwdU1qZ3hMakExTWkwdU5UWTFMakV3TXkwdU9EUTJMakUxTW1FdU1ETTJMakF6TmlBd0lEQWdNUzB1TURJMklEQnNNaTR4TkMwMUxqWXlOUzR3TURRdExqQXdNMk11TWprM0lERXVOekF5TGpVNUlETXVNemswTGpnNE5DQTFMakE1TWxwdExTNHhPRGN1TkRjNFl5MHhMakkyTmk0NE5Ua3RNaTQxTXpFZ01TNDNNakV0TXk0NElESXVOVGhzTGpjNE1TMHlMakExTkdNdU1EQTNMakF3TkM0d01UTWdNQ0F1TURJeklEQWdMamMxT1MwdU1UTXlJREV1TlRFMExTNHlOamdnTWk0eU55MHVOR3d1TmprM0xTNHhNall1TURNdExqQXdObU10TGpBd05DNHdNRE1nTUNBdU1EQTJJREFnTGpBd05sb2lJR1pwYkd3OUlpTXdNREFpTHo0OEwyYytQR2NnYVdROUluVnlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6ZEdOVFV6TXlJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSnNaV0ZtVW05M0lqNDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXdJaUI1UFNJd0lpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlMVEV5SWlCNVBTSXROeUl2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweU5DSWdlVDBpTFRFMElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlMVE0ySWlCNVBTSXRNakVpTHo0OEwyYytQQzlrWldaelBqeHlaV04wSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU16VXdJaUJ5ZUQwaU1UQWlJR1pwYkd3OUlpTXlOVE16TWpZaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnphV3h2SWlCNFBTSTVPU0lnZVQwaU5UVWlMejQ4WnlCcFpEMGlZV3hzVUd4dmRDSWdZMnhwY0Mxd1lYUm9QU0oxY213b0kySnZjbVJsY2sxaGMyc3BJajQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaUxURTJOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXRNVFkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTUNJZ2VUMGlMVEV5TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpFek9DSWdlVDBpTFRFeU5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMHhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTA0TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXdJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMDBOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTAyT1NJZ2VUMGlMVFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamMybHNieUlnZUQwaU5EY2lJSGs5SWpVMUlpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOeWtpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTB4TXpnaUlIazlJak0ySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l6TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkwMk9TSWdlVDBpTnpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR0Z5ZEdsaGJFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlOellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXdJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlqRXhOaUlnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXhOVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJakUxTmlJZ0x6NDhMMmMrUEhKbFkzUWdlRDBpTUNJZ2VUMGlNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1DSWdlVDBpTVRRdU5TSWdabTl1ZEMxemFYcGxQU0l4TWlJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKemRHRnlkQ0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1FrVkJUaUJFWlhCdmMybDBQQzkwWlhoMFBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkwSkZRVTRpSUhnOUlqSTBNQ0lnZVQwaU5DSWdMejQ4Y21WamRDQjRQU0l3SWlCNVBTSXpNekFpSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU1qQWlJSEo0UFNJMUlpQm1hV3hzUFNJak1qUXlOREkwSWk4K1BIUmxlSFFnZUQwaU1USTNJaUI1UFNJek5ETWlJR1p2Ym5RdGMybDZaVDBpTVRBaUlHWnBiR3c5SWxkb2FYUmxJaUIwWlhoMExXRnVZMmh2Y2owaWJXbGtaR3hsSWlCbWIyNTBMV1poYldsc2VUMGlablYwZFhKaElqNDhkSE53WVc0K1BHRnVhVzFoZEdVZ1lYUjBjbWxpZFhSbFRtRnRaVDBpZUNJZ1puSnZiVDBpTXpjMUlpQjBiejBpTlRBaUlHUjFjajBpTVRCeklpQnlaWEJsWVhSRGIzVnVkRDBpYVc1a1pXWnBibWwwWlNJZ0x6NHdlR0psWVRBd01EQXdNamxoWkRGak56ZGtNMlExWkRJelltRXlaRGc0T1ROa1lqbGtNV1ZtWVdJOEwzUnpjR0Z1UGp3dmRHVjRkRDQ4ZEdWNGRDQjRQU0l4TWpjaUlIazlJak0wTXlJZ1ptOXVkQzF6YVhwbFBTSXhNQ0lnWm1sc2JEMGlWMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0p0YVdSa2JHVWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGp4MGMzQmhiajQ4WVc1cGJXRjBaU0JoZEhSeWFXSjFkR1ZPWVcxbFBTSjRJaUJtY205dFBTSTFNQ0lnZEc4OUlpMHlOelVpSUdSMWNqMGlNVEJ6SWlCeVpYQmxZWFJEYjNWdWREMGlhVzVrWldacGJtbDBaU0lnTHo0d2VHSmxZVEF3TURBd01qbGhaREZqTnpka00yUTFaREl6WW1FeVpEZzRPVE5rWWpsa01XVm1ZV0k4TDNSemNHRnVQand2ZEdWNGRENDhkR1Y0ZENCNFBTSXlNelVpSUhrOUlqRTBMalVpSUdadmJuUXRjMmw2WlQwaU1USWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGlaVzVrSWlCbWIyNTBMV1poYldsc2VUMGlablYwZFhKaElqNVRkR1Z0T2lBeVBDOTBaWGgwUGp3dmMzWm5QZz09In0= \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJCRUFOIn0sIHsgInRyYWl0X3R5cGUiOiAiVG9rZW4gQWRkcmVzcyIsICJ2YWx1ZSI6ICIweGJlYTAwMDAwMjlhZDFjNzdkM2Q1ZDIzYmEyZDg4OTNkYjlkMWVmYWIifSwgeyAidHJhaXRfdHlwZSI6ICJJZCIsICJ2YWx1ZSI6ICIweGJlYTAwMDAwMjlhZDFjNzdkM2Q1ZDIzYmEyZDg4OTNkYjlkMWVmYWIwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDIifSwgeyAidHJhaXRfdHlwZSI6ICJzdGVtIiwgImRpc3BsYXlfdHlwZSI6ICJudW1iZXIiLCAidmFsdWUiOiAyfSwgeyAidHJhaXRfdHlwZSI6ICJpbml0YWwgc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMTAwMDB9LCB7ICJ0cmFpdF90eXBlIjogImdyb3duIHN0YWxrIHBlciBCRFYiLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDIwMDB9LCB7ICJ0cmFpdF90eXBlIjogInN0YWxrIGdyb3duIHBlciBCRFYgcGVyIHNlYXNvbiIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMjAwMDAwMCwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OEwyYytQR2NnYVdROUluQmhjblJwWVd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0dGeWRHbGhiRXhsWVdaU2IzY2lJSGc5SWkwMk1DSWdlVDBpTVRRaUlHWnBiR3c5SWlOQk9FTTRNMEVpSUhSeVlXNXpabTl5YlQwaWMyTmhiR1VvTVM0MEtTSXZQand2Wno0OFp5QnBaRDBpYkdWaFppSStQSEJoZEdnZ1pEMGlUVEUzTVM0NE9EUWdNVEU0TGprNE0yRTBMamt6TWlBMExqa3pNaUF3SURBZ01TMHhMakF4T0NBeUxqWXdOaUEwTGpjeE5TQTBMamN4TlNBd0lEQWdNUzB4TGpnM09DQXhMalF6T1dNdExqUTJOUzR4T1RVdE1TNDNNelV1TnpJM0xUSXVNelkwTGpFM05pMHVNalEySURNdU1qazRMVEV1TlRreklEWXVOVEV5TFRJdU1qVXpJRGN1T1RVMFlUUXVOVE15SURRdU5UTXlJREFnTUNBeExTNHpNVE10TGprek0yTXRMakl4TVMwdU9UYzFMUzR3TXpndE1TNDNOak11TURjNExUSXVNamsxTGpJd01pMHVPVEl4TGpNMU15MHhMall4TWk0ME5qY3RNaTR4TkMweExqRTNOeTQyT1RRdE1pNDJOREl1TlRZNUxUTXVOVFU0TFM0eU56SXRMamM1TmkwdU56TXlMVEV1TURnekxURXVPVEl4TFM0M05ETXRNeTR3TXpRdU5EazRMakF4TVNBeExqa3pPUzR4TURrZ015NHlORGNnTVM0eE5qZGhOUzR4TXlBMUxqRXpJREFnTUNBeElERXVNakVnTVM0ME1UTmpMakUxT1MwdU56UXVNVGs1TFM0NU5UZ3VNak00TFRFdU1UYzVMakl3T1MweExqSXhNeTR6TWpJdE1TNDROekl1TWpjMExUSXVOekkwWVRjdU56TWdOeTQzTXlBd0lEQWdNQzB1T1RBNExUTXVNVGMzWXkwdU56Y3lMalF4TlMweExqYzRPUzR4T1RZdE1pNHpOemd0TGpNd05DMHVNek01TFM0eU9EY3RMalUxTmkwdU5qZ3lMUzQzTmpRdE1TNDJPVEpoTVRJdU56TTVJREV5TGpjek9TQXdJREFnTVMwdU1UYzJMVE11T1RBNVl5NDNPRGt1TmpBeklERXVORGNnTVM0d01Ua2dNUzQ1TXpjZ01TNHlPRE11T1RRMExqVXpOaUF4TGpNME5DNDJNemtnTVM0M05qRWdNUzR4TmpjdU1UVXlMakU1TXk0Mk5Ea3VPRFF5TGpVNE5pQXhMamMxTVMwdU1ERXhMakUzTWkwdU1EVXpMamM1TlMwdU5EWTBJREV1TWprellUWXVPRE1nTmk0NE15QXdJREFnTVNBeExqTTROQ0F5TGpJeU4yTXVNVFF1TXpZNExqSTBNaTQzTkRRdU16RXhJREV1TVRVdU1UQTNMUzR5TURjdU1qWXhMUzQwTXprdU5URXhMUzQzTWpJdU5EVXpMUzQxTVRNdU9EY3RMams1TWlBeExqWXdOQzB4TGpJNE5DNDJPRE10TGpJM01pQXhMakk0TFM0eU5Ea2dNUzQzTWpNdExqSXpOR0UxTGpNd01pQTFMak13TWlBd0lEQWdNU0F4TGpRNE5pNHlOek5hSWk4K1BDOW5QanhuSUdsa1BTSnphV3h2SWo0OGNHRjBhQ0JrUFNKTk5UY3VNVEE0SURjeExqSTVZeTR4T0RndE1URXVOalV6TFRFeUxqQXhMVEl4TGpNd015MHlOeTR5TkRNdE1qRXVOVFV5TFRFMUxqSXpOQzB1TWpVdE1qY3VOek0ySURndU9UazFMVEkzTGpreU15QXlNQzQyTkRrdExqRTROeUF4TVM0Mk5UUWdNVEl1TURFZ01qRXVNekEwSURJM0xqSTBOQ0F5TVM0MU5UTWdNVFV1TWpNekxqSTFJREkzTGpjek5TMDRMams1TlNBeU55NDVNakl0TWpBdU5qVmFJaUJtYVd4c1BTSWpOalkySWk4K1BIQmhkR2dnWkQwaVRTNDBOalFnTVRrdU5UUTBZeTQyT1RrZ01UWXVOVGcxSURFdU5DQXpNeTR4TmprZ01pNHdPVGdnTkRrdU56VXlMakF5TVNBeUxqTTRNUzQwT0NBMExqSTNPQzQ0T0RNZ05TNDFNemt1TWpjM0xqZzJMamMwTVNBeUxqSTNOU0F4TGpjM09DQXpMamcyTnk0ME9UUXVOelU1SURFdU1qRXlJREV1TnlBekxqQXdNaUF6TGpNek1pQXhMamN6T1NBeExqVTROaUF6TGpNMUlETXVNRFUySURVdU56TXlJRFF1TXprNElETXVNamt6SURFdU9EVTFJRFl1TVRVeElESXVNemsySURndU56a3hJREl1T0RrMklERXVPRFUxTGpNMUlEVXVNVFE1TGprME9DQTVMalE0T0M0MU5UWmhNekl1TnpBM0lETXlMamN3TnlBd0lEQWdNQ0E1TGpNeE5TMHlMakk0TjJNeExqZzJNaTB1TnpVNUlEUXVOalF5TFRFdU9URTNJRGN1TmpNekxUUXVOQ0F4TGpNME9DMHhMakV5SURNdU5EUTRMVEl1T0RrM0lEVXVNVGszTFRVdU9UVmhNakF1TVRFMElESXdMakV4TkNBd0lEQWdNQ0F5TGpJMUxUVXVPVGs0WXk0eU1TMHhOeTQxTlRJdU5ESXRNelV1TVRBMExqWXpNaTAxTWk0Mk5UZHNMVFUyTGpndU9UVXlhQzR3TURGYUlpQm1hV3hzUFNJalFqTkNNMEl6SWk4K1BIQmhkR2dnWkQwaVRUVTNMalE0SURFNUxqUTRNa00xTnk0Mk5EVWdPUzR5TkNBME5DNDVOemd1TnpJM0lESTVMakU0Tnk0ME5qZ2dNVE11TXprM0xqSXhMalEyTXlBNExqTXdNeTR5T1RnZ01UZ3VOVFEyTGpFek5DQXlPQzQzT0RnZ01USXVPQ0F6Tnk0eklESTRMalU1TVNBek55NDFObU14TlM0M09TNHlOVGdnTWpndU56STBMVGN1T0RNMUlESTRMamc0T1MweE9DNHdOemhhSWlCbWFXeHNQU0lqUTBORElpOCtQSEJoZEdnZ1pEMGlUVE13TGpNeE5DQTNMakV6TjJNdU1EQTVMUzQxTmpFdExqWTRMVEV1TURJNExURXVOVE00TFRFdU1EUXlMUzQ0TlRrdExqQXhOQzB4TGpVMk1pNDBNeTB4TGpVM01TNDVPVEV0TGpBeExqVTJNaTQyT0NBeExqQXlPQ0F4TGpVek9DQXhMakEwTWk0NE5Ua3VNREUxSURFdU5UWXlMUzQwTXlBeExqVTNMUzQ1T1ZvaUlHWnBiR3c5SWlNMk5qWWlMejQ4Y0dGMGFDQmtQU0pOTmk0ME1UUWdNamd1T0RsaE1UVXVOemMzSURFMUxqYzNOeUF3SURBZ01TMHlMakE1TXkweUxqRTBObU10TGpnMU5pMHhMakEyTXkweUxqUTFNeTB6TGpBNU15MHlMamszTlMwMkxqRXhNbUV4TVM0M05qVWdNVEV1TnpZMUlEQWdNQ0F4TFM0d09UTXRNeTR6TURkc01qVXVORE10T1M0NU56WmpMakEwTXk0eE5ESXVNVGc0TGpVMU5TNDJNRFF1T0RZNExqUTJMak0wTmk0NU5EY3VNelFnTVM0d09EWXVNek0wVERZdU5ERXpJREk0TGpnNE9IWXVNREF5V2lJZ1ptbHNiRDBpSTBVMlJUWkZOaUl2UGp4d1lYUm9JRzl3WVdOcGRIazlJaTR6TXlJZ1pEMGlUVEV1TkRjM0lERTJMakF5T1dNdU1qVXRMamt6TVM0M01EWXRNaTR5TlRnZ01TNDFOeTB6TGpZNU5TNDJOVFV0TVM0d09USWdNUzR5T1RJdE1TNDRNalVnTVM0M05pMHlMak0xT0M0MU9EUXRMalkyTlNBeExqYzNOaTB4TGprek5DQXpMalkzT1MwekxqSTVJREl1T1RVekxUSXVNVEExSURVdU5qazJMVE11TURVZ055NDNNak10TXk0M00yRXpOeTR6TlNBek55NHpOU0F3SURBZ01TQTJMalE0TlMweExqVTBOMncxTGpJME1pQTBMak14Tm1FeExqUTRJREV1TkRnZ01DQXdJREF0TVM0eU1UUXVPVFkzVERFdU5EZ2dNVFl1TUROb0xTNHdNREphSWlCbWFXeHNQU0lqT1RrNUlpOCtQSEJoZEdnZ2IzQmhZMmwwZVQwaUxqUTBJaUJrUFNKTk1TNDRNU0F5Tmk0MU16SmpMakl3Tmk0ME9UUXVORGcwSURFdU1EVXVPRFlnTVM0Mk0yRXhNQzR5TmpZZ01UQXVNalkySURBZ01DQXdJREl1TWpjNElESXVORGcyVERZdU5UVXlJRGM0TGpJeVlURTNMakkzTWlBeE55NHlOeklnTUNBd0lERXRNeTAzTGpReE0wd3hMamd4SURJMkxqVXpNbG9pSUdacGJHdzlJaU5GTmtVMlJUWWlMejQ4Y0dGMGFDQmtQU0p0TXpNdU1Ea3lJRFE1TGpRME1TMDJMak00TVNBeE5TNHlNVEZ6TFRZdU1EYzRMVEV4TGpFMU9TQTJMak00TVMweE5TNHlNVm9pSUdacGJHdzlJaU00UlRoRk9FVWlMejQ4Y0dGMGFDQmtQU0p0TWpZdU56STFJRFkwTGpnMU9DMHVNRGt4TFM0eE56VmpMUzR3TWpZdExqQTBPUzB5TGpZek5DMDBMamt5TXkwdU9EWTNMVGt1TXpjZ01TNHdOVGN0TWk0M01UY2dNeTQxTVRndE5DNDNNalVnTnk0ekxUVXVPVFEyYkM0eE9EY3RMakEyTVMwMkxqVXpJREUxTGpVMU1scHROaTR5TVRJdE1UVXVNalk0WXkwekxqWXlNU0F4TGpJeE55MDFMams1TVNBekxqRTJPQzAzTGpBeU1pQTFMamM1T0MweExqVXpPQ0F6TGprd09DNHpOVFVnT0M0eE5qWXVOemc0SURrdU1EVTBiRFl1TWpNMExURTBMamcxTWxwTk1qZ3VNRGt6SURZekxqY3pOMncwTGpRNE5DMHhNQzQ0TjNNM0xqTTJOU0EyTGpNek55MDBMalE0TkNBeE1DNDROMW9pSUdacGJHdzlJaU00UlRoRk9FVWlMejQ4TDJjK1BHY2dhV1E5SWtKRlFVNGlQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTBOa0k1TlRVaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RjZ01TNHlOalV0TXk0MU1EUWdPUzR6TmxNdU1qazRJRE11T1RrNUlEY3VOamczSURFdU1qWTJXbTB0TWk0Mk9URWdPQzQzT0NBeUxqUTJNaTAyTGpZNU1YTTBMalV6T0NBekxqWTNMVEl1TkRZeUlEWXVOamt4V2lJZ1ptbHNiRDBpSTJabVppSXZQand2Wno0OFp5QnBaRDBpUWtWQlRqTkRVbFlpUGp4eVpXTjBJSGs5SWk0MUlpQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnM0lERXVOelkwTFRNdU5UQTBJRGt1TXpaVExqSTVPQ0EwTGpRNU9TQTNMalk0TnlBeExqYzJOVm9pSUdacGJHdzlJaU5tWm1ZaUx6NDhjR0YwYUNCa1BTSk5PQzR4TXpJZ09DNHdOemhqTFM0ME5qWXVOalF0TVM0eU9UY2dNUzR6TWpNdE1pNDJPVFVnTVM0NU9USnNNaTR4TWpZdE5TNDNOemRqTGpBNE9TNHdPUzR4T1RNdU1qQTBMak11TXpNNExqTXdNeTR6TnpVdU5qSTFMamc1TVM0M05EUWdNUzQwT0RRdU1URTNMalU0TXk0d05DQXhMakkxTXkwdU5EYzFJREV1T1RZeldpSWdabWxzYkQwaWRYSnNLQ05oS1NJZ2MzUnliMnRsUFNJalptWm1JaUJ6ZEhKdmEyVXRkMmxrZEdnOUlpNDFJaTgrUEdSbFpuTStQR3hwYm1WaGNrZHlZV1JwWlc1MElHbGtQU0poSWlCNE1UMGlOaTQ1TlNJZ2VURTlJak11T0RVeklpQjRNajBpTmk0NU5TSWdlVEk5SWpFd0xqVTBOQ0lnWjNKaFpHbGxiblJWYm1sMGN6MGlkWE5sY2xOd1lXTmxUMjVWYzJVaVBqeHpkRzl3SUhOMGIzQXRZMjlzYjNJOUlpTTRNakF5TURJaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWk0eE9ESWlJSE4wYjNBdFkyOXNiM0k5SWlOR056RkZNRFVpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJaTQxTVRZaUlITjBiM0F0WTI5c2IzSTlJaU5HTUVZMU1EY2lMejQ4YzNSdmNDQnZabVp6WlhROUlpNDNNelFpSUhOMGIzQXRZMjlzYjNJOUlpTTROVU5FTnpVaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWpFaUlITjBiM0F0WTI5c2IzSTlJaU13TWpsRVJrSWlMejQ4TDJ4cGJtVmhja2R5WVdScFpXNTBQand2WkdWbWN6NDhMMmMrUEdjZ2FXUTlJblZ5UWtWQlRpSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6ZEdOVFV6TXlJdlBqeHdZWFJvSUdROUltMDNMalk0TnlBeExqSTJOUzB6TGpVd05DQTVMak0yVXk0eU9UZ2dNeTQ1T1RrZ055NDJPRGNnTVM0eU5qWmFiUzB5TGpZNU1TQTRMamM0SURJdU5EWXlMVFl1TmpreGN6UXVOVE00SURNdU5qY3RNaTQwTmpJZ05pNDJPVEZhSWlCbWFXeHNQU0lqWm1abUlpOCtQQzluUGp4bklHbGtQU0pDUlVGT1JWUklJajQ4Y21WamRDQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnMElERXVNalkxTFRNdU5UQTFJRGt1TXpaakxqQXdNeUF3TFRNdU9EZzBMVFl1TmpJMUlETXVOVEExTFRrdU16WmFJaUJtYVd4c1BTSWpabVptSWk4K1BIQmhkR2dnWkQwaVRUZ3VPVFV5SURZdU9UZzJZUzR3TmpNdU1EWXpJREFnTUNBeExTNHdNakl1TURBell5MHVOekV1TVRNdE1TNDBNalF1TWpVMUxUSXVNVE0wTGpNNE1TMHVNamd4TGpBMU1pMHVOVFkxTGpFd015MHVPRFEyTGpFMU1tRXVNRE0yTGpBek5pQXdJREFnTVMwdU1ESTJJREJzTWk0eE5DMDFMall5TlM0d01EUXRMakF3TTJNdU1qazNJREV1TnpBeUxqVTVJRE11TXprMExqZzROQ0ExTGpBNU1scHRMUzR4T0RjdU5EYzRZeTB4TGpJMk5pNDROVGt0TWk0MU16RWdNUzQzTWpFdE15NDRJREl1TlRoc0xqYzRNUzB5TGpBMU5HTXVNREEzTGpBd05DNHdNVE1nTUNBdU1ESXpJREFnTGpjMU9TMHVNVE15SURFdU5URTBMUzR5TmpnZ01pNHlOeTB1Tkd3dU5qazNMUzR4TWpZdU1ETXRMakF3Tm1NdExqQXdOQzR3TURNZ01DQXVNREEySURBZ0xqQXdObG9pSUdacGJHdzlJaU13TURBaUx6NDhMMmMrUEdjZ2FXUTlJblZ5UWtWQlRrVlVTQ0krUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJemRHTlRVek15SXZQanh3WVhSb0lHUTlJbTAzTGpZNE5DQXhMakkyTlMwekxqVXdOU0E1TGpNMll5NHdNRE1nTUMwekxqZzROQzAyTGpZeU5TQXpMalV3TlMwNUxqTTJXaUlnWm1sc2JEMGlJMlptWmlJdlBqeHdZWFJvSUdROUlrMDRMamsxTWlBMkxqazRObUV1TURZekxqQTJNeUF3SURBZ01TMHVNREl5TGpBd00yTXRMamN4TGpFekxURXVOREkwTGpJMU5TMHlMakV6TkM0ek9ERXRMakk0TVM0d05USXRMalUyTlM0eE1ETXRMamcwTmk0eE5USmhMakF6Tmk0d016WWdNQ0F3SURFdExqQXlOaUF3YkRJdU1UUXROUzQyTWpVdU1EQTBMUzR3TUROakxqSTVOeUF4TGpjd01pNDFPU0F6TGpNNU5DNDRPRFFnTlM0d09USmFiUzB1TVRnM0xqUTNPR010TVM0eU5qWXVPRFU1TFRJdU5UTXhJREV1TnpJeExUTXVPQ0F5TGpVNGJDNDNPREV0TWk0d05UUmpMakF3Tnk0d01EUXVNREV6SURBZ0xqQXlNeUF3SUM0M05Ua3RMakV6TWlBeExqVXhOQzB1TWpZNElESXVNamN0TGpSc0xqWTVOeTB1TVRJMkxqQXpMUzR3TURaakxTNHdNRFF1TURBeklEQWdMakF3TmlBd0lDNHdNRFphSWlCbWFXeHNQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0pzWldGbVVtOTNJajQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5zWldGbUlpQjRQU0l3SWlCNVBTSXdJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTFRFeUlpQjVQU0l0TnlJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1lpSUhnOUlpMHlOQ0lnZVQwaUxURTBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTFRNMklpQjVQU0l0TWpFaUx6NDhMMmMrUEM5a1pXWnpQanh5WldOMElIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNelV3SWlCeWVEMGlNVEFpSUdacGJHdzlJaU15TlRNek1qWWlMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU56YVd4dklpQjRQU0k1T1NJZ2VUMGlOVFVpTHo0OFp5QnBaRDBpWVd4c1VHeHZkQ0lnWTJ4cGNDMXdZWFJvUFNKMWNtd29JMkp2Y21SbGNrMWhjMnNwSWo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTAyT1NJZ2VUMGlMVEUyTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l0TVRZMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU1DSWdlVDBpTFRFeU5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqRXpPQ0lnZVQwaUxURXlOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTB4TXpnaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWkwNE5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqWTVJaUI1UFNJdE9EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXRORFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l3SWlCNVBTSXRORFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l4TXpnaUlIazlJaTAwTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkwMk9TSWdlVDBpTFRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjMmxzYnlJZ2VEMGlORGNpSUhrOUlqVTFJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TnlraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkweE16Z2lJSGs5SWpNMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaU56WWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0dGeWRHbGhiRXhsWVdaUWJHOTBJaUI0UFNJMk9TSWdlVDBpTnpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l3SWlCNVBTSXhNVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l4TXpnaUlIazlJakV4TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l4TlRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpFMU5pSWdMejQ4TDJjK1BISmxZM1FnZUQwaU1DSWdlVDBpTUNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXlNQ0lnY25nOUlqVWlJR1pwYkd3OUlpTXlOREkwTWpRaUx6NDhkR1Y0ZENCNFBTSXhNQ0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSnpkR0Z5ZENJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStRa1ZCVGlCRVpYQnZjMmwwUEM5MFpYaDBQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMEpGUVU0aUlIZzlJakkwTUNJZ2VUMGlOQ0lnTHo0OGNtVmpkQ0I0UFNJd0lpQjVQU0l6TXpBaUlIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNakFpSUhKNFBTSTFJaUJtYVd4c1BTSWpNalF5TkRJMElpOCtQSFJsZUhRZ2VEMGlNVEkzSWlCNVBTSXpORE1pSUdadmJuUXRjMmw2WlQwaU1UQWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGliV2xrWkd4bElpQm1iMjUwTFdaaGJXbHNlVDBpWm5WMGRYSmhJajQ4ZEhOd1lXNCtQR0Z1YVcxaGRHVWdZWFIwY21saWRYUmxUbUZ0WlQwaWVDSWdabkp2YlQwaU16YzFJaUIwYnowaU5UQWlJR1IxY2owaU1UQnpJaUJ5WlhCbFlYUkRiM1Z1ZEQwaWFXNWtaV1pwYm1sMFpTSWdMejR3ZUdKbFlUQXdNREF3TWpsaFpERmpOemRrTTJRMVpESXpZbUV5WkRnNE9UTmtZamxrTVdWbVlXSThMM1J6Y0dGdVBqd3ZkR1Y0ZEQ0OGRHVjRkQ0I0UFNJeE1qY2lJSGs5SWpNME15SWdabTl1ZEMxemFYcGxQU0l4TUNJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKdGFXUmtiR1VpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBqeDBjM0JoYmo0OFlXNXBiV0YwWlNCaGRIUnlhV0oxZEdWT1lXMWxQU0o0SWlCbWNtOXRQU0kxTUNJZ2RHODlJaTB5TnpVaUlHUjFjajBpTVRCeklpQnlaWEJsWVhSRGIzVnVkRDBpYVc1a1pXWnBibWwwWlNJZ0x6NHdlR0psWVRBd01EQXdNamxoWkRGak56ZGtNMlExWkRJelltRXlaRGc0T1ROa1lqbGtNV1ZtWVdJOEwzUnpjR0Z1UGp3dmRHVjRkRDQ4ZEdWNGRDQjRQU0l5TXpVaUlIazlJakUwTGpVaUlHWnZiblF0YzJsNlpUMGlNVElpSUdacGJHdzlJbGRvYVhSbElpQjBaWGgwTFdGdVkyaHZjajBpWlc1a0lpQm1iMjUwTFdaaGJXbHNlVDBpWm5WMGRYSmhJajVUZEdWdE9pQXlQQzkwWlhoMFBqd3ZjM1puUGc9PSJ9 \ No newline at end of file diff --git a/protocol/test/data/base64EncodedImageBean3Crv.txt b/protocol/test/data/base64EncodedImageBean3Crv.txt index e3a0c1c14f..79776d64c2 100644 --- a/protocol/test/data/base64EncodedImageBean3Crv.txt +++ b/protocol/test/data/base64EncodedImageBean3Crv.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IEJFQU4zQ1JWXG5Ub2tlbiBBZGRyZXNzOiAweGM5YzMyY2QxNmJmN2VmYjg1ZmYxNGUwYzg2MDNjYzkwZjZmMmVlNDlcbklkOiAweGM5YzMyY2QxNmJmN2VmYjg1ZmYxNGUwYzg2MDNjYzkwZjZmMmVlNDkwMDAwMDAwMDAwMDAwMDAwMDAwMDAyMDBcbnN0ZW06IDUxMlxuaW5pdGFsIHN0YWxrIHBlciBCRFY6IDEwMDAwXG5ncm93biBzdGFsayBwZXIgQkRWOiAzNDkyXG5zdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb246IDQwMDAwMDBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCamJHRnpjejBpYzNablFtOWtlU0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJek5UQWlJSFpwWlhkQ2IzZzlJakFnTUNBeU5UVWdNelV3SWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhodGJHNXpPbmhzYVc1clBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJajQ4WkdWbWN6NDhaeUJwWkQwaWNHeHZkQ0krUEhCaGRHZ2daRDBpVFRjNUxqVTNNamdnTVRJNUxqSTJOVXd4TWpjdU5EWTVJREUxTmk0NE16Tk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UQXhMalk1TjB3M09TNDFOekk0SURFeU9TNHlOalZhSWlCbWFXeHNQU0lqT1RRMFFUSTNJaTgrUEhCaGRHZ2daRDBpVFRjNUxqVXpNeklnTVRNekxqUXlOa3czT1M0MU56STNJREV5T1M0eU5qVk1NVEkzTGpRMk9TQXhOVFl1T0RNelRERXlOeTQxTURjZ01UWXdMamt3T0V3M09TNDFNek15SURFek15NDBNalphSWlCbWFXeHNQU0lqTnpVek9URkdJaTgrUEhCaGRHZ2daRDBpVFRFM05TNDBOamNnTVRNekxqUk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UVTJMamd6TTB3eE1qY3VOVEEzSURFMk1DNDVNRGhNTVRjMUxqUTJOeUF4TXpNdU5Gb2lJR1pwYkd3OUlpTTJOek16TVVVaUx6NDhMMmMrUEdjZ2FXUTlJbVoxYkd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUWXdJaUI1UFNJeE5DSWdabWxzYkQwaUkwRTRRemd6UVNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUY3pJaUI1UFNJeU1TSWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKbGJYQjBlVkJzYjNRaVBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQnNiM1FpSUhnOUlpMHpOU0lnZVQwaU1DSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSndZWEowYVdGc1RHVmhabEp2ZHlJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaU1DSWdlVDBpTUNJdlBqd3ZaejQ4WnlCcFpEMGljR0Z5ZEdsaGJFeGxZV1pRYkc5MElqNDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTndiRzkwSWlCNFBTSXRNelVpSUhrOUlqQWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQmhjblJwWVd4TVpXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp3dlp6NDhaeUJwWkQwaWJHVmhaaUkrUEhCaGRHZ2daRDBpVFRFM01TNDRPRFFnTVRFNExqazRNMkUwTGprek1pQTBMamt6TWlBd0lEQWdNUzB4TGpBeE9DQXlMall3TmlBMExqY3hOU0EwTGpjeE5TQXdJREFnTVMweExqZzNPQ0F4TGpRek9XTXRMalEyTlM0eE9UVXRNUzQzTXpVdU56STNMVEl1TXpZMExqRTNOaTB1TWpRMklETXVNams0TFRFdU5Ua3pJRFl1TlRFeUxUSXVNalV6SURjdU9UVTBZVFF1TlRNeUlEUXVOVE15SURBZ01DQXhMUzR6TVRNdExqa3pNMk10TGpJeE1TMHVPVGMxTFM0d016Z3RNUzQzTmpNdU1EYzRMVEl1TWprMUxqSXdNaTB1T1RJeExqTTFNeTB4TGpZeE1pNDBOamN0TWk0eE5DMHhMakUzTnk0Mk9UUXRNaTQyTkRJdU5UWTVMVE11TlRVNExTNHlOekl0TGpjNU5pMHVOek15TFRFdU1EZ3pMVEV1T1RJeExTNDNORE10TXk0d016UXVORGs0TGpBeE1TQXhMamt6T1M0eE1Ea2dNeTR5TkRjZ01TNHhOamRoTlM0eE15QTFMakV6SURBZ01DQXhJREV1TWpFZ01TNDBNVE5qTGpFMU9TMHVOelF1TVRrNUxTNDVOVGd1TWpNNExURXVNVGM1TGpJd09TMHhMakl4TXk0ek1qSXRNUzQ0TnpJdU1qYzBMVEl1TnpJMFlUY3VOek1nTnk0M015QXdJREFnTUMwdU9UQTRMVE11TVRjM1l5MHVOemN5TGpReE5TMHhMamM0T1M0eE9UWXRNaTR6TnpndExqTXdOQzB1TXpNNUxTNHlPRGN0TGpVMU5pMHVOamd5TFM0M05qUXRNUzQyT1RKaE1USXVOek01SURFeUxqY3pPU0F3SURBZ01TMHVNVGMyTFRNdU9UQTVZeTQzT0RrdU5qQXpJREV1TkRjZ01TNHdNVGtnTVM0NU16Y2dNUzR5T0RNdU9UUTBMalV6TmlBeExqTTBOQzQyTXprZ01TNDNOakVnTVM0eE5qY3VNVFV5TGpFNU15NDJORGt1T0RReUxqVTROaUF4TGpjMU1TMHVNREV4TGpFM01pMHVNRFV6TGpjNU5TMHVORFkwSURFdU1qa3pZVFl1T0RNZ05pNDRNeUF3SURBZ01TQXhMak00TkNBeUxqSXlOMk11TVRRdU16WTRMakkwTWk0M05EUXVNekV4SURFdU1UVXVNVEEzTFM0eU1EY3VNall4TFM0ME16a3VOVEV4TFM0M01qSXVORFV6TFM0MU1UTXVPRGN0TGprNU1pQXhMall3TkMweExqSTROQzQyT0RNdExqSTNNaUF4TGpJNExTNHlORGtnTVM0M01qTXRMakl6TkdFMUxqTXdNaUExTGpNd01pQXdJREFnTVNBeExqUTROaTR5TnpOYUlpOCtQQzluUGp4bklHbGtQU0p6YVd4dklqNDhjR0YwYUNCa1BTSk5OVGN1TVRBNElEY3hMakk1WXk0eE9EZ3RNVEV1TmpVekxURXlMakF4TFRJeExqTXdNeTB5Tnk0eU5ETXRNakV1TlRVeUxURTFMakl6TkMwdU1qVXRNamN1TnpNMklEZ3VPVGsxTFRJM0xqa3lNeUF5TUM0Mk5Ea3RMakU0TnlBeE1TNDJOVFFnTVRJdU1ERWdNakV1TXpBMElESTNMakkwTkNBeU1TNDFOVE1nTVRVdU1qTXpMakkxSURJM0xqY3pOUzA0TGprNU5TQXlOeTQ1TWpJdE1qQXVOalZhSWlCbWFXeHNQU0lqTmpZMklpOCtQSEJoZEdnZ1pEMGlUUzQwTmpRZ01Ua3VOVFEwWXk0Mk9Ua2dNVFl1TlRnMUlERXVOQ0F6TXk0eE5qa2dNaTR3T1RnZ05Ea3VOelV5TGpBeU1TQXlMak00TVM0ME9DQTBMakkzT0M0NE9ETWdOUzQxTXprdU1qYzNMamcyTGpjME1TQXlMakkzTlNBeExqYzNPQ0F6TGpnMk55NDBPVFF1TnpVNUlERXVNakV5SURFdU55QXpMakF3TWlBekxqTXpNaUF4TGpjek9TQXhMalU0TmlBekxqTTFJRE11TURVMklEVXVOek15SURRdU16azRJRE11TWpreklERXVPRFUxSURZdU1UVXhJREl1TXprMklEZ3VOemt4SURJdU9EazJJREV1T0RVMUxqTTFJRFV1TVRRNUxqazBPQ0E1TGpRNE9DNDFOVFpoTXpJdU56QTNJRE15TGpjd055QXdJREFnTUNBNUxqTXhOUzB5TGpJNE4yTXhMamcyTWkwdU56VTVJRFF1TmpReUxURXVPVEUzSURjdU5qTXpMVFF1TkNBeExqTTBPQzB4TGpFeUlETXVORFE0TFRJdU9EazNJRFV1TVRrM0xUVXVPVFZoTWpBdU1URTBJREl3TGpFeE5DQXdJREFnTUNBeUxqSTFMVFV1T1RrNFl5NHlNUzB4Tnk0MU5USXVOREl0TXpVdU1UQTBMall6TWkwMU1pNDJOVGRzTFRVMkxqZ3VPVFV5YUM0d01ERmFJaUJtYVd4c1BTSWpRak5DTTBJeklpOCtQSEJoZEdnZ1pEMGlUVFUzTGpRNElERTVMalE0TWtNMU55NDJORFVnT1M0eU5DQTBOQzQ1TnpndU56STNJREk1TGpFNE55NDBOamdnTVRNdU16azNMakl4TGpRMk15QTRMak13TXk0eU9UZ2dNVGd1TlRRMkxqRXpOQ0F5T0M0M09EZ2dNVEl1T0NBek55NHpJREk0TGpVNU1TQXpOeTQxTm1NeE5TNDNPUzR5TlRnZ01qZ3VOekkwTFRjdU9ETTFJREk0TGpnNE9TMHhPQzR3TnpoYUlpQm1hV3hzUFNJalEwTkRJaTgrUEhCaGRHZ2daRDBpVFRNd0xqTXhOQ0EzTGpFek4yTXVNREE1TFM0MU5qRXRMalk0TFRFdU1ESTRMVEV1TlRNNExURXVNRFF5TFM0NE5Ua3RMakF4TkMweExqVTJNaTQwTXkweExqVTNNUzQ1T1RFdExqQXhMalUyTWk0Mk9DQXhMakF5T0NBeExqVXpPQ0F4TGpBME1pNDROVGt1TURFMUlERXVOVFl5TFM0ME15QXhMalUzTFM0NU9Wb2lJR1pwYkd3OUlpTTJOallpTHo0OGNHRjBhQ0JrUFNKTk5pNDBNVFFnTWpndU9EbGhNVFV1TnpjM0lERTFMamMzTnlBd0lEQWdNUzB5TGpBNU15MHlMakUwTm1NdExqZzFOaTB4TGpBMk15MHlMalExTXkwekxqQTVNeTB5TGprM05TMDJMakV4TW1FeE1TNDNOalVnTVRFdU56WTFJREFnTUNBeExTNHdPVE10TXk0ek1EZHNNalV1TkRNdE9TNDVOelpqTGpBME15NHhOREl1TVRnNExqVTFOUzQyTURRdU9EWTRMalEyTGpNME5pNDVORGN1TXpRZ01TNHdPRFl1TXpNMFREWXVOREV6SURJNExqZzRPSFl1TURBeVdpSWdabWxzYkQwaUkwVTJSVFpGTmlJdlBqeHdZWFJvSUc5d1lXTnBkSGs5SWk0ek15SWdaRDBpVFRFdU5EYzNJREUyTGpBeU9XTXVNalV0TGprek1TNDNNRFl0TWk0eU5UZ2dNUzQxTnkwekxqWTVOUzQyTlRVdE1TNHdPVElnTVM0eU9USXRNUzQ0TWpVZ01TNDNOaTB5TGpNMU9DNDFPRFF0TGpZMk5TQXhMamMzTmkweExqa3pOQ0F6TGpZM09TMHpMakk1SURJdU9UVXpMVEl1TVRBMUlEVXVOamsyTFRNdU1EVWdOeTQzTWpNdE15NDNNMkV6Tnk0ek5TQXpOeTR6TlNBd0lEQWdNU0EyTGpRNE5TMHhMalUwTjJ3MUxqSTBNaUEwTGpNeE5tRXhMalE0SURFdU5EZ2dNQ0F3SURBdE1TNHlNVFF1T1RZM1RERXVORGdnTVRZdU1ETm9MUzR3TURKYUlpQm1hV3hzUFNJak9UazVJaTgrUEhCaGRHZ2diM0JoWTJsMGVUMGlMalEwSWlCa1BTSk5NUzQ0TVNBeU5pNDFNekpqTGpJd05pNDBPVFF1TkRnMElERXVNRFV1T0RZZ01TNDJNMkV4TUM0eU5qWWdNVEF1TWpZMklEQWdNQ0F3SURJdU1qYzRJREl1TkRnMlREWXVOVFV5SURjNExqSXlZVEUzTGpJM01pQXhOeTR5TnpJZ01DQXdJREV0TXkwM0xqUXhNMHd4TGpneElESTJMalV6TWxvaUlHWnBiR3c5SWlORk5rVTJSVFlpTHo0OGNHRjBhQ0JrUFNKdE16TXVNRGt5SURRNUxqUTBNUzAyTGpNNE1TQXhOUzR5TVRGekxUWXVNRGM0TFRFeExqRTFPU0EyTGpNNE1TMHhOUzR5TVZvaUlHWnBiR3c5SWlNNFJUaEZPRVVpTHo0OGNHRjBhQ0JrUFNKdE1qWXVOekkxSURZMExqZzFPQzB1TURreExTNHhOelZqTFM0d01qWXRMakEwT1MweUxqWXpOQzAwTGpreU15MHVPRFkzTFRrdU16Y2dNUzR3TlRjdE1pNDNNVGNnTXk0MU1UZ3ROQzQzTWpVZ055NHpMVFV1T1RRMmJDNHhPRGN0TGpBMk1TMDJMalV6SURFMUxqVTFNbHB0Tmk0eU1USXRNVFV1TWpZNFl5MHpMall5TVNBeExqSXhOeTAxTGprNU1TQXpMakUyT0MwM0xqQXlNaUExTGpjNU9DMHhMalV6T0NBekxqa3dPQzR6TlRVZ09DNHhOall1TnpnNElEa3VNRFUwYkRZdU1qTTBMVEUwTGpnMU1scE5Namd1TURreklEWXpMamN6TjJ3MExqUTROQzB4TUM0NE4zTTNMak0yTlNBMkxqTXpOeTAwTGpRNE5DQXhNQzQ0TjFvaUlHWnBiR3c5SWlNNFJUaEZPRVVpTHo0OEwyYytQR2NnYVdROUlrSkZRVTRpUGp4eVpXTjBJSGRwWkhSb1BTSXhNaUlnYUdWcFoyaDBQU0l4TWlJZ2NuZzlJallpSUdacGJHdzlJaU0wTmtJNU5UVWlMejQ4Y0dGMGFDQmtQU0p0Tnk0Mk9EY2dNUzR5TmpVdE15NDFNRFFnT1M0ek5sTXVNams0SURNdU9UazVJRGN1TmpnM0lERXVNalkyV20wdE1pNDJPVEVnT0M0M09DQXlMalEyTWkwMkxqWTVNWE0wTGpVek9DQXpMalkzTFRJdU5EWXlJRFl1TmpreFdpSWdabWxzYkQwaUkyWm1aaUl2UGp3dlp6NDhaeUJwWkQwaVFrVkJUak5EVWxZaVBqeHlaV04wSUhrOUlpNDFJaUIzYVdSMGFEMGlNVElpSUdobGFXZG9kRDBpTVRJaUlISjRQU0kySWlCbWFXeHNQU0lqTkRaQ09UVTFJaTgrUEhCaGRHZ2daRDBpYlRjdU5qZzNJREV1TnpZMExUTXVOVEEwSURrdU16WlRMakk1T0NBMExqUTVPU0EzTGpZNE55QXhMamMyTlZvaUlHWnBiR3c5SWlObVptWWlMejQ4Y0dGMGFDQmtQU0pOT0M0eE16SWdPQzR3TnpoakxTNDBOall1TmpRdE1TNHlPVGNnTVM0ek1qTXRNaTQyT1RVZ01TNDVPVEpzTWk0eE1qWXROUzQzTnpkakxqQTRPUzR3T1M0eE9UTXVNakEwTGpNdU16TTRMak13TXk0ek56VXVOakkxTGpnNU1TNDNORFFnTVM0ME9EUXVNVEUzTGpVNE15NHdOQ0F4TGpJMU15MHVORGMxSURFdU9UWXpXaUlnWm1sc2JEMGlkWEpzS0NOaEtTSWdjM1J5YjJ0bFBTSWpabVptSWlCemRISnZhMlV0ZDJsa2RHZzlJaTQxSWk4K1BHUmxabk0rUEd4cGJtVmhja2R5WVdScFpXNTBJR2xrUFNKaElpQjRNVDBpTmk0NU5TSWdlVEU5SWpNdU9EVXpJaUI0TWowaU5pNDVOU0lnZVRJOUlqRXdMalUwTkNJZ1ozSmhaR2xsYm5SVmJtbDBjejBpZFhObGNsTndZV05sVDI1VmMyVWlQanh6ZEc5d0lITjBiM0F0WTI5c2IzSTlJaU00TWpBeU1ESWlMejQ4YzNSdmNDQnZabVp6WlhROUlpNHhPRElpSUhOMGIzQXRZMjlzYjNJOUlpTkdOekZGTURVaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWk0MU1UWWlJSE4wYjNBdFkyOXNiM0k5SWlOR01FWTFNRGNpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJaTQzTXpRaUlITjBiM0F0WTI5c2IzSTlJaU00TlVORU56VWlMejQ4YzNSdmNDQnZabVp6WlhROUlqRWlJSE4wYjNBdFkyOXNiM0k5SWlNd01qbEVSa0lpTHo0OEwyeHBibVZoY2tkeVlXUnBaVzUwUGp3dlpHVm1jejQ4TDJjK1BHY2dhV1E5SW5WeVFrVkJUaUkrUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJemRHTlRVek15SXZQanh3WVhSb0lHUTlJbTAzTGpZNE55QXhMakkyTlMwekxqVXdOQ0E1TGpNMlV5NHlPVGdnTXk0NU9Ua2dOeTQyT0RjZ01TNHlOalphYlMweUxqWTVNU0E0TGpjNElESXVORFl5TFRZdU5qa3hjelF1TlRNNElETXVOamN0TWk0ME5qSWdOaTQyT1RGYUlpQm1hV3hzUFNJalptWm1JaTgrUEM5blBqeG5JR2xrUFNKQ1JVRk9SVlJJSWo0OGNtVmpkQ0IzYVdSMGFEMGlNVElpSUdobGFXZG9kRDBpTVRJaUlISjRQU0kySWlCbWFXeHNQU0lqTkRaQ09UVTFJaTgrUEhCaGRHZ2daRDBpYlRjdU5qZzBJREV1TWpZMUxUTXVOVEExSURrdU16WmpMakF3TXlBd0xUTXVPRGcwTFRZdU5qSTFJRE11TlRBMUxUa3VNelphSWlCbWFXeHNQU0lqWm1abUlpOCtQSEJoZEdnZ1pEMGlUVGd1T1RVeUlEWXVPVGcyWVM0d05qTXVNRFl6SURBZ01DQXhMUzR3TWpJdU1EQXpZeTB1TnpFdU1UTXRNUzQwTWpRdU1qVTFMVEl1TVRNMExqTTRNUzB1TWpneExqQTFNaTB1TlRZMUxqRXdNeTB1T0RRMkxqRTFNbUV1TURNMkxqQXpOaUF3SURBZ01TMHVNREkySURCc01pNHhOQzAxTGpZeU5TNHdNRFF0TGpBd00yTXVNamszSURFdU56QXlMalU1SURNdU16azBMamc0TkNBMUxqQTVNbHB0TFM0eE9EY3VORGM0WXkweExqSTJOaTQ0TlRrdE1pNDFNekVnTVM0M01qRXRNeTQ0SURJdU5UaHNMamM0TVMweUxqQTFOR011TURBM0xqQXdOQzR3TVRNZ01DQXVNREl6SURBZ0xqYzFPUzB1TVRNeUlERXVOVEUwTFM0eU5qZ2dNaTR5TnkwdU5Hd3VOamszTFM0eE1qWXVNRE10TGpBd05tTXRMakF3TkM0d01ETWdNQ0F1TURBMklEQWdMakF3TmxvaUlHWnBiR3c5SWlNd01EQWlMejQ4TDJjK1BHY2dhV1E5SW5WeVFrVkJUa1ZVU0NJK1BISmxZM1FnZDJsa2RHZzlJakV5SWlCb1pXbG5hSFE5SWpFeUlpQnllRDBpTmlJZ1ptbHNiRDBpSXpkR05UVXpNeUl2UGp4d1lYUm9JR1E5SW0wM0xqWTROQ0F4TGpJMk5TMHpMalV3TlNBNUxqTTJZeTR3TURNZ01DMHpMamc0TkMwMkxqWXlOU0F6TGpVd05TMDVMak0yV2lJZ1ptbHNiRDBpSTJabVppSXZQanh3WVhSb0lHUTlJazA0TGprMU1pQTJMams0Tm1FdU1EWXpMakEyTXlBd0lEQWdNUzB1TURJeUxqQXdNMk10TGpjeExqRXpMVEV1TkRJMExqSTFOUzB5TGpFek5DNHpPREV0TGpJNE1TNHdOVEl0TGpVMk5TNHhNRE10TGpnME5pNHhOVEpoTGpBek5pNHdNellnTUNBd0lERXRMakF5TmlBd2JESXVNVFF0TlM0Mk1qVXVNREEwTFM0d01ETmpMakk1TnlBeExqY3dNaTQxT1NBekxqTTVOQzQ0T0RRZ05TNHdPVEphYlMwdU1UZzNMalEzT0dNdE1TNHlOall1T0RVNUxUSXVOVE14SURFdU56SXhMVE11T0NBeUxqVTRiQzQzT0RFdE1pNHdOVFJqTGpBd055NHdNRFF1TURFeklEQWdMakF5TXlBd0lDNDNOVGt0TGpFek1pQXhMalV4TkMwdU1qWTRJREl1TWpjdExqUnNMalk1TnkwdU1USTJMakF6TFM0d01EWmpMUzR3TURRdU1EQXpJREFnTGpBd05pQXdJQzR3TURaYUlpQm1hV3hzUFNJak1EQXdJaTgrUEM5blBqeG5JR2xrUFNKc1pXRm1VbTkzSWo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1JaUI0UFNJd0lpQjVQU0l3SWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaUxURXlJaUI1UFNJdE55SXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB5TkNJZ2VUMGlMVEUwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaUxUTTJJaUI1UFNJdE1qRWlMejQ4TDJjK1BDOWtaV1p6UGp4eVpXTjBJSGRwWkhSb1BTSXlOVFVpSUdobGFXZG9kRDBpTXpVd0lpQnllRDBpTVRBaUlHWnBiR3c5SWlNeU5UTXpNallpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOemFXeHZJaUI0UFNJNU9TSWdlVDBpTlRVaUx6NDhaeUJwWkQwaVlXeHNVR3h2ZENJZ1kyeHBjQzF3WVhSb1BTSjFjbXdvSTJKdmNtUmxjazFoYzJzcElqNDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkwMk9TSWdlVDBpTFRFMk5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqWTVJaUI1UFNJdE1UWTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNQ0lnZVQwaUxURXlOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJakV6T0NJZ2VUMGlMVEV5TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWkweE16Z2lJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXROamtpSUhrOUlpMDROQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXRPRFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJd0lpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJeE16Z2lJSGs5SWkwME5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaUxUUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSTJPU0lnZVQwaUxUUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYzJsc2J5SWdlRDBpTkRjaUlIazlJalUxSWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU55a2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMHhNemdpSUhrOUlqTTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNCaGNuUnBZV3hNWldGbVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaU56WWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlOellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXdJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlqRXhOaUlnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXhOVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJakUxTmlJZ0x6NDhMMmMrUEhKbFkzUWdlRDBpTUNJZ2VUMGlNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1DSWdlVDBpTVRRdU5TSWdabTl1ZEMxemFYcGxQU0l4TWlJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKemRHRnlkQ0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1FrVkJUak5EVWxZZ1JHVndiM05wZER3dmRHVjRkRDQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5DUlVGT00wTlNWaUlnZUQwaU1qUXdJaUI1UFNJMElpQXZQanh5WldOMElIZzlJakFpSUhrOUlqTXpNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1qY2lJSGs5SWpNME15SWdabTl1ZEMxemFYcGxQU0l4TUNJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKdGFXUmtiR1VpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBqeDBjM0JoYmo0OFlXNXBiV0YwWlNCaGRIUnlhV0oxZEdWT1lXMWxQU0o0SWlCbWNtOXRQU0l6TnpVaUlIUnZQU0kxTUNJZ1pIVnlQU0l4TUhNaUlISmxjR1ZoZEVOdmRXNTBQU0pwYm1SbFptbHVhWFJsSWlBdlBqQjRZemxqTXpKalpERTJZbVkzWldaaU9EVm1aakUwWlRCak9EWXdNMk5qT1RCbU5tWXlaV1UwT1R3dmRITndZVzQrUEM5MFpYaDBQangwWlhoMElIZzlJakV5TnlJZ2VUMGlNelF6SWlCbWIyNTBMWE5wZW1VOUlqRXdJaUJtYVd4c1BTSlhhR2wwWlNJZ2RHVjRkQzFoYm1Ob2IzSTlJbTFwWkdSc1pTSWdabTl1ZEMxbVlXMXBiSGs5SW1aMWRIVnlZU0krUEhSemNHRnVQanhoYm1sdFlYUmxJR0YwZEhKcFluVjBaVTVoYldVOUluZ2lJR1p5YjIwOUlqVXdJaUIwYnowaUxUSTNOU0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNFl6bGpNekpqWkRFMlltWTNaV1ppT0RWbVpqRTBaVEJqT0RZd00yTmpPVEJtTm1ZeVpXVTBPVHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqSXpOU0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSmxibVFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBsTjBaVzA2SURVeE1qd3ZkR1Y0ZEQ0OEwzTjJaejQ9In0= \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJCRUFOM0NSViJ9LCB7ICJ0cmFpdF90eXBlIjogIlRva2VuIEFkZHJlc3MiLCAidmFsdWUiOiAiMHhjOWMzMmNkMTZiZjdlZmI4NWZmMTRlMGM4NjAzY2M5MGY2ZjJlZTQ5In0sIHsgInRyYWl0X3R5cGUiOiAiSWQiLCAidmFsdWUiOiAiMHhjOWMzMmNkMTZiZjdlZmI4NWZmMTRlMGM4NjAzY2M5MGY2ZjJlZTQ5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMjAwIn0sIHsgInRyYWl0X3R5cGUiOiAic3RlbSIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogNTEyfSwgeyAidHJhaXRfdHlwZSI6ICJpbml0YWwgc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMTAwMDB9LCB7ICJ0cmFpdF90eXBlIjogImdyb3duIHN0YWxrIHBlciBCRFYiLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDM0OTJ9LCB7ICJ0cmFpdF90eXBlIjogInN0YWxrIGdyb3duIHBlciBCRFYgcGVyIHNlYXNvbiIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogNDAwMDAwMCwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQand2Wno0OFp5QnBaRDBpY0dGeWRHbGhiRXhsWVdaUWJHOTBJajQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU53Ykc5MElpQjRQU0l0TXpVaUlIazlJakFpSUhSeVlXNXpabTl5YlQwaWMyTmhiR1VvTVM0MEtTSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JoY25ScFlXeE1aV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmlJK1BIQmhkR2dnWkQwaVRURTNNUzQ0T0RRZ01URTRMams0TTJFMExqa3pNaUEwTGprek1pQXdJREFnTVMweExqQXhPQ0F5TGpZd05pQTBMamN4TlNBMExqY3hOU0F3SURBZ01TMHhMamczT0NBeExqUXpPV010TGpRMk5TNHhPVFV0TVM0M016VXVOekkzTFRJdU16WTBMakUzTmkwdU1qUTJJRE11TWprNExURXVOVGt6SURZdU5URXlMVEl1TWpVeklEY3VPVFUwWVRRdU5UTXlJRFF1TlRNeUlEQWdNQ0F4TFM0ek1UTXRMamt6TTJNdExqSXhNUzB1T1RjMUxTNHdNemd0TVM0M05qTXVNRGM0TFRJdU1qazFMakl3TWkwdU9USXhMak0xTXkweExqWXhNaTQwTmpjdE1pNHhOQzB4TGpFM055NDJPVFF0TWk0Mk5ESXVOVFk1TFRNdU5UVTRMUzR5TnpJdExqYzVOaTB1TnpNeUxURXVNRGd6TFRFdU9USXhMUzQzTkRNdE15NHdNelF1TkRrNExqQXhNU0F4TGprek9TNHhNRGtnTXk0eU5EY2dNUzR4TmpkaE5TNHhNeUExTGpFeklEQWdNQ0F4SURFdU1qRWdNUzQwTVROakxqRTFPUzB1TnpRdU1UazVMUzQ1TlRndU1qTTRMVEV1TVRjNUxqSXdPUzB4TGpJeE15NHpNakl0TVM0NE56SXVNamMwTFRJdU56STBZVGN1TnpNZ055NDNNeUF3SURBZ01DMHVPVEE0TFRNdU1UYzNZeTB1TnpjeUxqUXhOUzB4TGpjNE9TNHhPVFl0TWk0ek56Z3RMak13TkMwdU16TTVMUzR5T0RjdExqVTFOaTB1TmpneUxTNDNOalF0TVM0Mk9USmhNVEl1TnpNNUlERXlMamN6T1NBd0lEQWdNUzB1TVRjMkxUTXVPVEE1WXk0M09Ea3VOakF6SURFdU5EY2dNUzR3TVRrZ01TNDVNemNnTVM0eU9ETXVPVFEwTGpVek5pQXhMak0wTkM0Mk16a2dNUzQzTmpFZ01TNHhOamN1TVRVeUxqRTVNeTQyTkRrdU9EUXlMalU0TmlBeExqYzFNUzB1TURFeExqRTNNaTB1TURVekxqYzVOUzB1TkRZMElERXVNamt6WVRZdU9ETWdOaTQ0TXlBd0lEQWdNU0F4TGpNNE5DQXlMakl5TjJNdU1UUXVNelk0TGpJME1pNDNORFF1TXpFeElERXVNVFV1TVRBM0xTNHlNRGN1TWpZeExTNDBNemt1TlRFeExTNDNNakl1TkRVekxTNDFNVE11T0RjdExqazVNaUF4TGpZd05DMHhMakk0TkM0Mk9ETXRMakkzTWlBeExqSTRMUzR5TkRrZ01TNDNNak10TGpJek5HRTFMak13TWlBMUxqTXdNaUF3SURBZ01TQXhMalE0Tmk0eU56TmFJaTgrUEM5blBqeG5JR2xrUFNKemFXeHZJajQ4Y0dGMGFDQmtQU0pOTlRjdU1UQTRJRGN4TGpJNVl5NHhPRGd0TVRFdU5qVXpMVEV5TGpBeExUSXhMak13TXkweU55NHlORE10TWpFdU5UVXlMVEUxTGpJek5DMHVNalV0TWpjdU56TTJJRGd1T1RrMUxUSTNMamt5TXlBeU1DNDJORGt0TGpFNE55QXhNUzQyTlRRZ01USXVNREVnTWpFdU16QTBJREkzTGpJME5DQXlNUzQxTlRNZ01UVXVNak16TGpJMUlESTNMamN6TlMwNExqazVOU0F5Tnk0NU1qSXRNakF1TmpWYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFM0ME5qUWdNVGt1TlRRMFl5NDJPVGtnTVRZdU5UZzFJREV1TkNBek15NHhOamtnTWk0d09UZ2dORGt1TnpVeUxqQXlNU0F5TGpNNE1TNDBPQ0EwTGpJM09DNDRPRE1nTlM0MU16a3VNamMzTGpnMkxqYzBNU0F5TGpJM05TQXhMamMzT0NBekxqZzJOeTQwT1RRdU56VTVJREV1TWpFeUlERXVOeUF6TGpBd01pQXpMak16TWlBeExqY3pPU0F4TGpVNE5pQXpMak0xSURNdU1EVTJJRFV1TnpNeUlEUXVNems0SURNdU1qa3pJREV1T0RVMUlEWXVNVFV4SURJdU16azJJRGd1TnpreElESXVPRGsySURFdU9EVTFMak0xSURVdU1UUTVMamswT0NBNUxqUTRPQzQxTlRaaE16SXVOekEzSURNeUxqY3dOeUF3SURBZ01DQTVMak14TlMweUxqSTROMk14TGpnMk1pMHVOelU1SURRdU5qUXlMVEV1T1RFM0lEY3VOak16TFRRdU5DQXhMak0wT0MweExqRXlJRE11TkRRNExUSXVPRGszSURVdU1UazNMVFV1T1RWaE1qQXVNVEUwSURJd0xqRXhOQ0F3SURBZ01DQXlMakkxTFRVdU9UazRZeTR5TVMweE55NDFOVEl1TkRJdE16VXVNVEEwTGpZek1pMDFNaTQyTlRkc0xUVTJMamd1T1RVeWFDNHdNREZhSWlCbWFXeHNQU0lqUWpOQ00wSXpJaTgrUEhCaGRHZ2daRDBpVFRVM0xqUTRJREU1TGpRNE1rTTFOeTQyTkRVZ09TNHlOQ0EwTkM0NU56Z3VOekkzSURJNUxqRTROeTQwTmpnZ01UTXVNemszTGpJeExqUTJNeUE0TGpNd015NHlPVGdnTVRndU5UUTJMakV6TkNBeU9DNDNPRGdnTVRJdU9DQXpOeTR6SURJNExqVTVNU0F6Tnk0MU5tTXhOUzQzT1M0eU5UZ2dNamd1TnpJMExUY3VPRE0xSURJNExqZzRPUzB4T0M0d056aGFJaUJtYVd4c1BTSWpRME5ESWk4K1BIQmhkR2dnWkQwaVRUTXdMak14TkNBM0xqRXpOMk11TURBNUxTNDFOakV0TGpZNExURXVNREk0TFRFdU5UTTRMVEV1TURReUxTNDROVGt0TGpBeE5DMHhMalUyTWk0ME15MHhMalUzTVM0NU9URXRMakF4TGpVMk1pNDJPQ0F4TGpBeU9DQXhMalV6T0NBeExqQTBNaTQ0TlRrdU1ERTFJREV1TlRZeUxTNDBNeUF4TGpVM0xTNDVPVm9pSUdacGJHdzlJaU0yTmpZaUx6NDhjR0YwYUNCa1BTSk5OaTQwTVRRZ01qZ3VPRGxoTVRVdU56YzNJREUxTGpjM055QXdJREFnTVMweUxqQTVNeTB5TGpFME5tTXRMamcxTmkweExqQTJNeTB5TGpRMU15MHpMakE1TXkweUxqazNOUzAyTGpFeE1tRXhNUzQzTmpVZ01URXVOelkxSURBZ01DQXhMUzR3T1RNdE15NHpNRGRzTWpVdU5ETXRPUzQ1TnpaakxqQTBNeTR4TkRJdU1UZzRMalUxTlM0Mk1EUXVPRFk0TGpRMkxqTTBOaTQ1TkRjdU16UWdNUzR3T0RZdU16TTBURFl1TkRFeklESTRMamc0T0hZdU1EQXlXaUlnWm1sc2JEMGlJMFUyUlRaRk5pSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNHpNeUlnWkQwaVRURXVORGMzSURFMkxqQXlPV011TWpVdExqa3pNUzQzTURZdE1pNHlOVGdnTVM0MU55MHpMalk1TlM0Mk5UVXRNUzR3T1RJZ01TNHlPVEl0TVM0NE1qVWdNUzQzTmkweUxqTTFPQzQxT0RRdExqWTJOU0F4TGpjM05pMHhMamt6TkNBekxqWTNPUzB6TGpJNUlESXVPVFV6TFRJdU1UQTFJRFV1TmprMkxUTXVNRFVnTnk0M01qTXRNeTQzTTJFek55NHpOU0F6Tnk0ek5TQXdJREFnTVNBMkxqUTROUzB4TGpVME4ydzFMakkwTWlBMExqTXhObUV4TGpRNElERXVORGdnTUNBd0lEQXRNUzR5TVRRdU9UWTNUREV1TkRnZ01UWXVNRE5vTFM0d01ESmFJaUJtYVd4c1BTSWpPVGs1SWk4K1BIQmhkR2dnYjNCaFkybDBlVDBpTGpRMElpQmtQU0pOTVM0NE1TQXlOaTQxTXpKakxqSXdOaTQwT1RRdU5EZzBJREV1TURVdU9EWWdNUzQyTTJFeE1DNHlOallnTVRBdU1qWTJJREFnTUNBd0lESXVNamM0SURJdU5EZzJURFl1TlRVeUlEYzRMakl5WVRFM0xqSTNNaUF4Tnk0eU56SWdNQ0F3SURFdE15MDNMalF4TTB3eExqZ3hJREkyTGpVek1sb2lJR1pwYkd3OUlpTkZOa1UyUlRZaUx6NDhjR0YwYUNCa1BTSnRNek11TURreUlEUTVMalEwTVMwMkxqTTRNU0F4TlM0eU1URnpMVFl1TURjNExURXhMakUxT1NBMkxqTTRNUzB4TlM0eU1Wb2lJR1pwYkd3OUlpTTRSVGhGT0VVaUx6NDhjR0YwYUNCa1BTSnRNall1TnpJMUlEWTBMamcxT0MwdU1Ea3hMUzR4TnpWakxTNHdNall0TGpBME9TMHlMall6TkMwMExqa3lNeTB1T0RZM0xUa3VNemNnTVM0d05UY3RNaTQzTVRjZ015NDFNVGd0TkM0M01qVWdOeTR6TFRVdU9UUTJiQzR4T0RjdExqQTJNUzAyTGpVeklERTFMalUxTWxwdE5pNHlNVEl0TVRVdU1qWTRZeTB6TGpZeU1TQXhMakl4TnkwMUxqazVNU0F6TGpFMk9DMDNMakF5TWlBMUxqYzVPQzB4TGpVek9DQXpMamt3T0M0ek5UVWdPQzR4TmpZdU56ZzRJRGt1TURVMGJEWXVNak0wTFRFMExqZzFNbHBOTWpndU1Ea3pJRFl6TGpjek4ydzBMalE0TkMweE1DNDROM00zTGpNMk5TQTJMak16TnkwMExqUTROQ0F4TUM0NE4xb2lJR1pwYkd3OUlpTTRSVGhGT0VVaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNME5rSTVOVFVpTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGpORFVsWWlQanh5WldOMElIazlJaTQxSWlCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU56WTBMVE11TlRBMElEa3VNelpUTGpJNU9DQTBMalE1T1NBM0xqWTROeUF4TGpjMk5Wb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNHhNeklnT0M0d056aGpMUzQwTmpZdU5qUXRNUzR5T1RjZ01TNHpNak10TWk0Mk9UVWdNUzQ1T1RKc01pNHhNall0TlM0M056ZGpMakE0T1M0d09TNHhPVE11TWpBMExqTXVNek00TGpNd015NHpOelV1TmpJMUxqZzVNUzQzTkRRZ01TNDBPRFF1TVRFM0xqVTRNeTR3TkNBeExqSTFNeTB1TkRjMUlERXVPVFl6V2lJZ1ptbHNiRDBpZFhKc0tDTmhLU0lnYzNSeWIydGxQU0lqWm1abUlpQnpkSEp2YTJVdGQybGtkR2c5SWk0MUlpOCtQR1JsWm5NK1BHeHBibVZoY2tkeVlXUnBaVzUwSUdsa1BTSmhJaUI0TVQwaU5pNDVOU0lnZVRFOUlqTXVPRFV6SWlCNE1qMGlOaTQ1TlNJZ2VUSTlJakV3TGpVME5DSWdaM0poWkdsbGJuUlZibWwwY3owaWRYTmxjbE53WVdObFQyNVZjMlVpUGp4emRHOXdJSE4wYjNBdFkyOXNiM0k5SWlNNE1qQXlNRElpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJaTR4T0RJaUlITjBiM0F0WTI5c2IzSTlJaU5HTnpGRk1EVWlMejQ4YzNSdmNDQnZabVp6WlhROUlpNDFNVFlpSUhOMGIzQXRZMjlzYjNJOUlpTkdNRVkxTURjaUx6NDhjM1J2Y0NCdlptWnpaWFE5SWk0M016UWlJSE4wYjNBdFkyOXNiM0k5SWlNNE5VTkVOelVpTHo0OGMzUnZjQ0J2Wm1aelpYUTlJakVpSUhOMGIzQXRZMjlzYjNJOUlpTXdNamxFUmtJaUx6NDhMMnhwYm1WaGNrZHlZV1JwWlc1MFBqd3ZaR1ZtY3o0OEwyYytQR2NnYVdROUluVnlRa1ZCVGlJK1BISmxZM1FnZDJsa2RHZzlJakV5SWlCb1pXbG5hSFE5SWpFeUlpQnllRDBpTmlJZ1ptbHNiRDBpSXpkR05UVXpNeUl2UGp4d1lYUm9JR1E5SW0wM0xqWTROeUF4TGpJMk5TMHpMalV3TkNBNUxqTTJVeTR5T1RnZ015NDVPVGtnTnk0Mk9EY2dNUzR5TmpaYWJTMHlMalk1TVNBNExqYzRJREl1TkRZeUxUWXVOamt4Y3pRdU5UTTRJRE11TmpjdE1pNDBOaklnTmk0Mk9URmFJaUJtYVd4c1BTSWpabVptSWk4K1BDOW5QanhuSUdsa1BTSkNSVUZPUlZSSUlqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamcwSURFdU1qWTFMVE11TlRBMUlEa3VNelpqTGpBd015QXdMVE11T0RnMExUWXVOakkxSURNdU5UQTFMVGt1TXpaYUlpQm1hV3hzUFNJalptWm1JaTgrUEhCaGRHZ2daRDBpVFRndU9UVXlJRFl1T1RnMllTNHdOak11TURZeklEQWdNQ0F4TFM0d01qSXVNREF6WXkwdU56RXVNVE10TVM0ME1qUXVNalUxTFRJdU1UTTBMak00TVMwdU1qZ3hMakExTWkwdU5UWTFMakV3TXkwdU9EUTJMakUxTW1FdU1ETTJMakF6TmlBd0lEQWdNUzB1TURJMklEQnNNaTR4TkMwMUxqWXlOUzR3TURRdExqQXdNMk11TWprM0lERXVOekF5TGpVNUlETXVNemswTGpnNE5DQTFMakE1TWxwdExTNHhPRGN1TkRjNFl5MHhMakkyTmk0NE5Ua3RNaTQxTXpFZ01TNDNNakV0TXk0NElESXVOVGhzTGpjNE1TMHlMakExTkdNdU1EQTNMakF3TkM0d01UTWdNQ0F1TURJeklEQWdMamMxT1MwdU1UTXlJREV1TlRFMExTNHlOamdnTWk0eU55MHVOR3d1TmprM0xTNHhNall1TURNdExqQXdObU10TGpBd05DNHdNRE1nTUNBdU1EQTJJREFnTGpBd05sb2lJR1pwYkd3OUlpTXdNREFpTHo0OEwyYytQR2NnYVdROUluVnlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6ZEdOVFV6TXlJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSnNaV0ZtVW05M0lqNDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXdJaUI1UFNJd0lpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlMVEV5SWlCNVBTSXROeUl2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweU5DSWdlVDBpTFRFMElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlMVE0ySWlCNVBTSXRNakVpTHo0OEwyYytQQzlrWldaelBqeHlaV04wSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU16VXdJaUJ5ZUQwaU1UQWlJR1pwYkd3OUlpTXlOVE16TWpZaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnphV3h2SWlCNFBTSTVPU0lnZVQwaU5UVWlMejQ4WnlCcFpEMGlZV3hzVUd4dmRDSWdZMnhwY0Mxd1lYUm9QU0oxY213b0kySnZjbVJsY2sxaGMyc3BJajQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMDJPU0lnZVQwaUxURTJOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJalk1SWlCNVBTSXRNVFkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTUNJZ2VUMGlMVEV5TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpFek9DSWdlVDBpTFRFeU5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlpMHhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTA0TkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXdJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMDBOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTAyT1NJZ2VUMGlMVFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamMybHNieUlnZUQwaU5EY2lJSGs5SWpVMUlpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOeWtpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTB4TXpnaUlIazlJak0ySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQmhjblJwWVd4TVpXRm1VR3h2ZENJZ2VEMGlNVE00SWlCNVBTSXpOaUlnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObGJYQjBlVkJzYjNRaUlIZzlJaTAyT1NJZ2VUMGlOellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJMk9TSWdlVDBpTnpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l3SWlCNVBTSXhNVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l4TXpnaUlIazlJakV4TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpZNUlpQjVQU0l4TlRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpFMU5pSWdMejQ4TDJjK1BISmxZM1FnZUQwaU1DSWdlVDBpTUNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXlNQ0lnY25nOUlqVWlJR1pwYkd3OUlpTXlOREkwTWpRaUx6NDhkR1Y0ZENCNFBTSXhNQ0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSnpkR0Z5ZENJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStRa1ZCVGpORFVsWWdSR1Z3YjNOcGREd3ZkR1Y0ZEQ0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOQ1JVRk9NME5TVmlJZ2VEMGlNalF3SWlCNVBTSTBJaUF2UGp4eVpXTjBJSGc5SWpBaUlIazlJak16TUNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXlNQ0lnY25nOUlqVWlJR1pwYkd3OUlpTXlOREkwTWpRaUx6NDhkR1Y0ZENCNFBTSXhNamNpSUhrOUlqTTBNeUlnWm05dWRDMXphWHBsUFNJeE1DSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSnRhV1JrYkdVaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQangwYzNCaGJqNDhZVzVwYldGMFpTQmhkSFJ5YVdKMWRHVk9ZVzFsUFNKNElpQm1jbTl0UFNJek56VWlJSFJ2UFNJMU1DSWdaSFZ5UFNJeE1ITWlJSEpsY0dWaGRFTnZkVzUwUFNKcGJtUmxabWx1YVhSbElpQXZQakI0WXpsak16SmpaREUyWW1ZM1pXWmlPRFZtWmpFMFpUQmpPRFl3TTJOak9UQm1ObVl5WldVME9Ud3ZkSE53WVc0K1BDOTBaWGgwUGp4MFpYaDBJSGc5SWpFeU55SWdlVDBpTXpReklpQm1iMjUwTFhOcGVtVTlJakV3SWlCbWFXeHNQU0pYYUdsMFpTSWdkR1Y0ZEMxaGJtTm9iM0k5SW0xcFpHUnNaU0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1BIUnpjR0Z1UGp4aGJtbHRZWFJsSUdGMGRISnBZblYwWlU1aGJXVTlJbmdpSUdaeWIyMDlJalV3SWlCMGJ6MGlMVEkzTlNJZ1pIVnlQU0l4TUhNaUlISmxjR1ZoZEVOdmRXNTBQU0pwYm1SbFptbHVhWFJsSWlBdlBqQjRZemxqTXpKalpERTJZbVkzWldaaU9EVm1aakUwWlRCak9EWXdNMk5qT1RCbU5tWXlaV1UwT1R3dmRITndZVzQrUEM5MFpYaDBQangwWlhoMElIZzlJakl6TlNJZ2VUMGlNVFF1TlNJZ1ptOXVkQzF6YVhwbFBTSXhNaUlnWm1sc2JEMGlWMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0psYm1RaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQbE4wWlcwNklEVXhNand2ZEdWNGRENDhMM04yWno0PSJ9 \ No newline at end of file diff --git a/protocol/test/data/base64EncodedImageBeanEth.txt b/protocol/test/data/base64EncodedImageBeanEth.txt index ca01c52418..c1a46d1a4e 100644 --- a/protocol/test/data/base64EncodedImageBeanEth.txt +++ b/protocol/test/data/base64EncodedImageBeanEth.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IEJFQU5FVEhcblRva2VuIEFkZHJlc3M6IDB4YmVhMGUxMTI4MmUyYmI1ODkzYmVjZTExMGNmMTk5NTAxZTg3MmJhZFxuSWQ6IDB4YmVhMGUxMTI4MmUyYmI1ODkzYmVjZTExMGNmMTk5NTAxZTg3MmJhZGZmZmZmZmZmZmZmZmYwMDAwMDAwMDAwMlxuc3RlbTogLTE3NTkyMTg2MDQ0NDE0XG5pbml0YWwgc3RhbGsgcGVyIEJEVjogMTAwMDBcbmdyb3duIHN0YWxrIHBlciBCRFY6IDE3NTkyMTg2MDQ4NDE4XG5zdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb246IDQwMDAwMDBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCamJHRnpjejBpYzNablFtOWtlU0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJek5UQWlJSFpwWlhkQ2IzZzlJakFnTUNBeU5UVWdNelV3SWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhodGJHNXpPbmhzYVc1clBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJajQ4WkdWbWN6NDhaeUJwWkQwaWNHeHZkQ0krUEhCaGRHZ2daRDBpVFRjNUxqVTNNamdnTVRJNUxqSTJOVXd4TWpjdU5EWTVJREUxTmk0NE16Tk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UQXhMalk1TjB3M09TNDFOekk0SURFeU9TNHlOalZhSWlCbWFXeHNQU0lqT1RRMFFUSTNJaTgrUEhCaGRHZ2daRDBpVFRjNUxqVXpNeklnTVRNekxqUXlOa3czT1M0MU56STNJREV5T1M0eU5qVk1NVEkzTGpRMk9TQXhOVFl1T0RNelRERXlOeTQxTURjZ01UWXdMamt3T0V3M09TNDFNek15SURFek15NDBNalphSWlCbWFXeHNQU0lqTnpVek9URkdJaTgrUEhCaGRHZ2daRDBpVFRFM05TNDBOamNnTVRNekxqUk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UVTJMamd6TTB3eE1qY3VOVEEzSURFMk1DNDVNRGhNTVRjMUxqUTJOeUF4TXpNdU5Gb2lJR1pwYkd3OUlpTTJOek16TVVVaUx6NDhMMmMrUEdjZ2FXUTlJbVoxYkd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUWXdJaUI1UFNJeE5DSWdabWxzYkQwaUkwRTRRemd6UVNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUY3pJaUI1UFNJeU1TSWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKbGJYQjBlVkJzYjNRaVBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQnNiM1FpSUhnOUlpMHpOU0lnZVQwaU1DSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSndZWEowYVdGc1RHVmhabEp2ZHlJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaU1DSWdlVDBpTUNJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1lpSUhnOUlpMHhNaUlnZVQwaUxUY2lMejQ4TDJjK1BHY2dhV1E5SW5CaGNuUnBZV3hNWldGbVVHeHZkQ0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0d4dmRDSWdlRDBpTFRNMUlpQjVQU0l3SWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU53WVhKMGFXRnNUR1ZoWmxKdmR5SWdlRDBpTFRNMUlpQjVQU0l3SWlCbWFXeHNQU0lqUVRoRE9ETkJJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhMMmMrUEdjZ2FXUTlJbXhsWVdZaVBqeHdZWFJvSUdROUlrMHhOekV1T0RnMElERXhPQzQ1T0ROaE5DNDVNeklnTkM0NU16SWdNQ0F3SURFdE1TNHdNVGdnTWk0Mk1EWWdOQzQzTVRVZ05DNDNNVFVnTUNBd0lERXRNUzQ0TnpnZ01TNDBNemxqTFM0ME5qVXVNVGsxTFRFdU56TTFMamN5TnkweUxqTTJOQzR4TnpZdExqSTBOaUF6TGpJNU9DMHhMalU1TXlBMkxqVXhNaTB5TGpJMU15QTNMamsxTkdFMExqVXpNaUEwTGpVek1pQXdJREFnTVMwdU16RXpMUzQ1TXpOakxTNHlNVEV0TGprM05TMHVNRE00TFRFdU56WXpMakEzT0MweUxqSTVOUzR5TURJdExqa3lNUzR6TlRNdE1TNDJNVEl1TkRZM0xUSXVNVFF0TVM0eE56Y3VOamswTFRJdU5qUXlMalUyT1MwekxqVTFPQzB1TWpjeUxTNDNPVFl0TGpjek1pMHhMakE0TXkweExqa3lNUzB1TnpRekxUTXVNRE0wTGpRNU9DNHdNVEVnTVM0NU16a3VNVEE1SURNdU1qUTNJREV1TVRZM1lUVXVNVE1nTlM0eE15QXdJREFnTVNBeExqSXhJREV1TkRFell5NHhOVGt0TGpjMExqRTVPUzB1T1RVNExqSXpPQzB4TGpFM09TNHlNRGt0TVM0eU1UTXVNekl5TFRFdU9EY3lMakkzTkMweUxqY3lOR0UzTGpjeklEY3VOek1nTUNBd0lEQXRMamt3T0MwekxqRTNOMk10TGpjM01pNDBNVFV0TVM0M09Ea3VNVGsyTFRJdU16YzRMUzR6TURRdExqTXpPUzB1TWpnM0xTNDFOVFl0TGpZNE1pMHVOelkwTFRFdU5qa3lZVEV5TGpjek9TQXhNaTQzTXprZ01DQXdJREV0TGpFM05pMHpMamt3T1dNdU56ZzVMall3TXlBeExqUTNJREV1TURFNUlERXVPVE0zSURFdU1qZ3pMamswTkM0MU16WWdNUzR6TkRRdU5qTTVJREV1TnpZeElERXVNVFkzTGpFMU1pNHhPVE11TmpRNUxqZzBNaTQxT0RZZ01TNDNOVEV0TGpBeE1TNHhOekl0TGpBMU15NDNPVFV0TGpRMk5DQXhMakk1TTJFMkxqZ3pJRFl1T0RNZ01DQXdJREVnTVM0ek9EUWdNaTR5TWpkakxqRTBMak0yT0M0eU5ESXVOelEwTGpNeE1TQXhMakUxTGpFd055MHVNakEzTGpJMk1TMHVORE01TGpVeE1TMHVOekl5TGpRMU15MHVOVEV6TGpnM0xTNDVPVElnTVM0Mk1EUXRNUzR5T0RRdU5qZ3pMUzR5TnpJZ01TNHlPQzB1TWpRNUlERXVOekl6TFM0eU16UmhOUzR6TURJZ05TNHpNRElnTUNBd0lERWdNUzQwT0RZdU1qY3pXaUl2UGp3dlp6NDhaeUJwWkQwaWMybHNieUkrUEhCaGRHZ2daRDBpVFRVM0xqRXdPQ0EzTVM0eU9XTXVNVGc0TFRFeExqWTFNeTB4TWk0d01TMHlNUzR6TURNdE1qY3VNalF6TFRJeExqVTFNaTB4TlM0eU16UXRMakkxTFRJM0xqY3pOaUE0TGprNU5TMHlOeTQ1TWpNZ01qQXVOalE1TFM0eE9EY2dNVEV1TmpVMElERXlMakF4SURJeExqTXdOQ0F5Tnk0eU5EUWdNakV1TlRVeklERTFMakl6TXk0eU5TQXlOeTQzTXpVdE9DNDVPVFVnTWpjdU9USXlMVEl3TGpZMVdpSWdabWxzYkQwaUl6WTJOaUl2UGp4d1lYUm9JR1E5SWswdU5EWTBJREU1TGpVME5HTXVOams1SURFMkxqVTROU0F4TGpRZ016TXVNVFk1SURJdU1EazRJRFE1TGpjMU1pNHdNakVnTWk0ek9ERXVORGdnTkM0eU56Z3VPRGd6SURVdU5UTTVMakkzTnk0NE5pNDNOREVnTWk0eU56VWdNUzQzTnpnZ015NDROamN1TkRrMExqYzFPU0F4TGpJeE1pQXhMamNnTXk0d01ESWdNeTR6TXpJZ01TNDNNemtnTVM0MU9EWWdNeTR6TlNBekxqQTFOaUExTGpjek1pQTBMak01T0NBekxqSTVNeUF4TGpnMU5TQTJMakUxTVNBeUxqTTVOaUE0TGpjNU1TQXlMamc1TmlBeExqZzFOUzR6TlNBMUxqRTBPUzQ1TkRnZ09TNDBPRGd1TlRVMllUTXlMamN3TnlBek1pNDNNRGNnTUNBd0lEQWdPUzR6TVRVdE1pNHlPRGRqTVM0NE5qSXRMamMxT1NBMExqWTBNaTB4TGpreE55QTNMall6TXkwMExqUWdNUzR6TkRndE1TNHhNaUF6TGpRME9DMHlMamc1TnlBMUxqRTVOeTAxTGprMVlUSXdMakV4TkNBeU1DNHhNVFFnTUNBd0lEQWdNaTR5TlMwMUxqazVPR011TWpFdE1UY3VOVFV5TGpReUxUTTFMakV3TkM0Mk16SXROVEl1TmpVM2JDMDFOaTQ0TGprMU1tZ3VNREF4V2lJZ1ptbHNiRDBpSTBJelFqTkNNeUl2UGp4d1lYUm9JR1E5SWswMU55NDBPQ0F4T1M0ME9ESkROVGN1TmpRMUlEa3VNalFnTkRRdU9UYzRMamN5TnlBeU9TNHhPRGN1TkRZNElERXpMak01Tnk0eU1TNDBOak1nT0M0ek1ETXVNams0SURFNExqVTBOaTR4TXpRZ01qZ3VOemc0SURFeUxqZ2dNemN1TXlBeU9DNDFPVEVnTXpjdU5UWmpNVFV1TnprdU1qVTRJREk0TGpjeU5DMDNMamd6TlNBeU9DNDRPRGt0TVRndU1EYzRXaUlnWm1sc2JEMGlJME5EUXlJdlBqeHdZWFJvSUdROUlrMHpNQzR6TVRRZ055NHhNemRqTGpBd09TMHVOVFl4TFM0Mk9DMHhMakF5T0MweExqVXpPQzB4TGpBME1pMHVPRFU1TFM0d01UUXRNUzQxTmpJdU5ETXRNUzQxTnpFdU9Ua3hMUzR3TVM0MU5qSXVOamdnTVM0d01qZ2dNUzQxTXpnZ01TNHdOREl1T0RVNUxqQXhOU0F4TGpVMk1pMHVORE1nTVM0MU55MHVPVGxhSWlCbWFXeHNQU0lqTmpZMklpOCtQSEJoZEdnZ1pEMGlUVFl1TkRFMElESTRMamc1WVRFMUxqYzNOeUF4TlM0M056Y2dNQ0F3SURFdE1pNHdPVE10TWk0eE5EWmpMUzQ0TlRZdE1TNHdOak10TWk0ME5UTXRNeTR3T1RNdE1pNDVOelV0Tmk0eE1USmhNVEV1TnpZMUlERXhMamMyTlNBd0lEQWdNUzB1TURrekxUTXVNekEzYkRJMUxqUXpMVGt1T1RjMll5NHdORE11TVRReUxqRTRPQzQxTlRVdU5qQTBMamcyT0M0ME5pNHpORFl1T1RRM0xqTTBJREV1TURnMkxqTXpORXcyTGpReE15QXlPQzQ0T0RoMkxqQXdNbG9pSUdacGJHdzlJaU5GTmtVMlJUWWlMejQ4Y0dGMGFDQnZjR0ZqYVhSNVBTSXVNek1pSUdROUlrMHhMalEzTnlBeE5pNHdNamxqTGpJMUxTNDVNekV1TnpBMkxUSXVNalU0SURFdU5UY3RNeTQyT1RVdU5qVTFMVEV1TURreUlERXVNamt5TFRFdU9ESTFJREV1TnpZdE1pNHpOVGd1TlRnMExTNDJOalVnTVM0M056WXRNUzQ1TXpRZ015NDJOemt0TXk0eU9TQXlMamsxTXkweUxqRXdOU0ExTGpZNU5pMHpMakExSURjdU56SXpMVE11TnpOaE16Y3VNelVnTXpjdU16VWdNQ0F3SURFZ05pNDBPRFV0TVM0MU5EZHNOUzR5TkRJZ05DNHpNVFpoTVM0ME9DQXhMalE0SURBZ01DQXdMVEV1TWpFMExqazJOMHd4TGpRNElERTJMakF6YUMwdU1EQXlXaUlnWm1sc2JEMGlJems1T1NJdlBqeHdZWFJvSUc5d1lXTnBkSGs5SWk0ME5DSWdaRDBpVFRFdU9ERWdNall1TlRNeVl5NHlNRFl1TkRrMExqUTROQ0F4TGpBMUxqZzJJREV1TmpOaE1UQXVNalkySURFd0xqSTJOaUF3SURBZ01DQXlMakkzT0NBeUxqUTROa3cyTGpVMU1pQTNPQzR5TW1FeE55NHlOeklnTVRjdU1qY3lJREFnTUNBeExUTXROeTQwTVROTU1TNDRNU0F5Tmk0MU16SmFJaUJtYVd4c1BTSWpSVFpGTmtVMklpOCtQSEJoZEdnZ1pEMGliVE16TGpBNU1pQTBPUzQwTkRFdE5pNHpPREVnTVRVdU1qRXhjeTAyTGpBM09DMHhNUzR4TlRrZ05pNHpPREV0TVRVdU1qRmFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQSEJoZEdnZ1pEMGliVEkyTGpjeU5TQTJOQzQ0TlRndExqQTVNUzB1TVRjMVl5MHVNREkyTFM0d05Ea3RNaTQyTXpRdE5DNDVNak10TGpnMk55MDVMak0zSURFdU1EVTNMVEl1TnpFM0lETXVOVEU0TFRRdU56STFJRGN1TXkwMUxqazBObXd1TVRnM0xTNHdOakV0Tmk0MU15QXhOUzQxTlRKYWJUWXVNakV5TFRFMUxqSTJPR010TXk0Mk1qRWdNUzR5TVRjdE5TNDVPVEVnTXk0eE5qZ3ROeTR3TWpJZ05TNDNPVGd0TVM0MU16Z2dNeTQ1TURndU16VTFJRGd1TVRZMkxqYzRPQ0E1TGpBMU5HdzJMakl6TkMweE5DNDROVEphVFRJNExqQTVNeUEyTXk0M016ZHNOQzQwT0RRdE1UQXVPRGR6Tnk0ek5qVWdOaTR6TXpjdE5DNDBPRFFnTVRBdU9EZGFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQQzluUGp4bklHbGtQU0pDUlVGT0lqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU1qWTFMVE11TlRBMElEa3VNelpUTGpJNU9DQXpMams1T1NBM0xqWTROeUF4TGpJMk5scHRMVEl1TmpreElEZ3VOemdnTWk0ME5qSXROaTQyT1RGek5DNDFNemdnTXk0Mk55MHlMalEyTWlBMkxqWTVNVm9pSUdacGJHdzlJaU5tWm1ZaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0elExSldJajQ4Y21WamRDQjVQU0l1TlNJZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TnlBeExqYzJOQzB6TGpVd05DQTVMak0yVXk0eU9UZ2dOQzQwT1RrZ055NDJPRGNnTVM0M05qVmFJaUJtYVd4c1BTSWpabVptSWk4K1BIQmhkR2dnWkQwaVRUZ3VNVE15SURndU1EYzRZeTB1TkRZMkxqWTBMVEV1TWprM0lERXVNekl6TFRJdU5qazFJREV1T1RreWJESXVNVEkyTFRVdU56YzNZeTR3T0RrdU1Ea3VNVGt6TGpJd05DNHpMak16T0M0ek1ETXVNemMxTGpZeU5TNDRPVEV1TnpRMElERXVORGcwTGpFeE55NDFPRE11TURRZ01TNHlOVE10TGpRM05TQXhMamsyTTFvaUlHWnBiR3c5SW5WeWJDZ2pZU2tpSUhOMGNtOXJaVDBpSTJabVppSWdjM1J5YjJ0bExYZHBaSFJvUFNJdU5TSXZQanhrWldaelBqeHNhVzVsWVhKSGNtRmthV1Z1ZENCcFpEMGlZU0lnZURFOUlqWXVPVFVpSUhreFBTSXpMamcxTXlJZ2VESTlJall1T1RVaUlIa3lQU0l4TUM0MU5EUWlJR2R5WVdScFpXNTBWVzVwZEhNOUluVnpaWEpUY0dGalpVOXVWWE5sSWo0OGMzUnZjQ0J6ZEc5d0xXTnZiRzl5UFNJak9ESXdNakF5SWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TVRneUlpQnpkRzl3TFdOdmJHOXlQU0lqUmpjeFJUQTFJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOVEUySWlCemRHOXdMV052Ykc5eVBTSWpSakJHTlRBM0lpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU56TTBJaUJ6ZEc5d0xXTnZiRzl5UFNJak9EVkRSRGMxSWk4K1BITjBiM0FnYjJabWMyVjBQU0l4SWlCemRHOXdMV052Ykc5eVBTSWpNREk1UkVaQ0lpOCtQQzlzYVc1bFlYSkhjbUZrYVdWdWRENDhMMlJsWm5NK1BDOW5QanhuSUdsa1BTSjFja0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNM1JqVTFNek1pTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSjFja0pGUVU1RlZFZ2lQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RRZ01TNHlOalV0TXk0MU1EVWdPUzR6Tm1NdU1EQXpJREF0TXk0NE9EUXROaTQyTWpVZ015NDFNRFV0T1M0ek5sb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNDVOVElnTmk0NU9EWmhMakEyTXk0d05qTWdNQ0F3SURFdExqQXlNaTR3TUROakxTNDNNUzR4TXkweExqUXlOQzR5TlRVdE1pNHhNelF1TXpneExTNHlPREV1TURVeUxTNDFOalV1TVRBekxTNDRORFl1TVRVeVlTNHdNell1TURNMklEQWdNQ0F4TFM0d01qWWdNR3d5TGpFMExUVXVOakkxTGpBd05DMHVNREF6WXk0eU9UY2dNUzQzTURJdU5Ua2dNeTR6T1RRdU9EZzBJRFV1TURreVdtMHRMakU0Tnk0ME56aGpMVEV1TWpZMkxqZzFPUzB5TGpVek1TQXhMamN5TVMwekxqZ2dNaTQxT0d3dU56Z3hMVEl1TURVMFl5NHdNRGN1TURBMExqQXhNeUF3SUM0d01qTWdNQ0F1TnpVNUxTNHhNeklnTVM0MU1UUXRMakkyT0NBeUxqSTNMUzQwYkM0Mk9UY3RMakV5Tmk0d015MHVNREEyWXkwdU1EQTBMakF3TXlBd0lDNHdNRFlnTUNBdU1EQTJXaUlnWm1sc2JEMGlJekF3TUNJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1JaUI0UFNJdE1qUWlJSGs5SWkweE5DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB6TmlJZ2VUMGlMVEl4SWk4K1BDOW5Qand2WkdWbWN6NDhjbVZqZENCM2FXUjBhRDBpTWpVMUlpQm9aV2xuYUhROUlqTTFNQ0lnY25nOUlqRXdJaUJtYVd4c1BTSWpNalV6TXpJMklpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjMmxzYnlJZ2VEMGlPVGtpSUhrOUlqVTFJaTgrUEdjZ2FXUTlJbUZzYkZCc2IzUWlJR05zYVhBdGNHRjBhRDBpZFhKc0tDTmliM0prWlhKTllYTnJLU0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l0TmpraUlIazlJaTB4TmpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSTJPU0lnZVQwaUxURTJOQ0lnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObWRXeHNUR1ZoWmxCc2IzUWlJSGc5SWpBaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJdE1USTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSTJPU0lnZVQwaUxUZzBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTFRFek9DSWdlVDBpTFRRMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlNQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTVRNNElpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXROamtpSUhrOUlpMDBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzTnBiRzhpSUhnOUlqUTNJaUI1UFNJMU5TSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMamNwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5tZFd4c1RHVmhabEJzYjNRaUlIZzlJakV6T0NJZ2VUMGlNellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlOamtpSUhrOUlqYzJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTFRFek9DSWdlVDBpTVRFMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlNQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSTJPU0lnZVQwaU1UVTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l4TlRZaUlDOCtQQzluUGp4eVpXTjBJSGc5SWpBaUlIazlJakFpSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU1qQWlJSEo0UFNJMUlpQm1hV3hzUFNJak1qUXlOREkwSWk4K1BIUmxlSFFnZUQwaU1UQWlJSGs5SWpFMExqVWlJR1p2Ym5RdGMybDZaVDBpTVRJaUlHWnBiR3c5SWxkb2FYUmxJaUIwWlhoMExXRnVZMmh2Y2owaWMzUmhjblFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBrSkZRVTVGVkVnZ1JHVndiM05wZER3dmRHVjRkRDQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5DUlVGT1JWUklJaUI0UFNJeU5EQWlJSGs5SWpRaUlDOCtQSEpsWTNRZ2VEMGlNQ0lnZVQwaU16TXdJaUIzYVdSMGFEMGlNalUxSWlCb1pXbG5hSFE5SWpJd0lpQnllRDBpTlNJZ1ptbHNiRDBpSXpJME1qUXlOQ0l2UGp4MFpYaDBJSGc5SWpFeU55SWdlVDBpTXpReklpQm1iMjUwTFhOcGVtVTlJakV3SWlCbWFXeHNQU0pYYUdsMFpTSWdkR1Y0ZEMxaGJtTm9iM0k5SW0xcFpHUnNaU0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1BIUnpjR0Z1UGp4aGJtbHRZWFJsSUdGMGRISnBZblYwWlU1aGJXVTlJbmdpSUdaeWIyMDlJak0zTlNJZ2RHODlJalV3SWlCa2RYSTlJakV3Y3lJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUM4K01IaGlaV0V3WlRFeE1qZ3laVEppWWpVNE9UTmlaV05sTVRFd1kyWXhPVGsxTURGbE9EY3lZbUZrUEM5MGMzQmhiajQ4TDNSbGVIUStQSFJsZUhRZ2VEMGlNVEkzSWlCNVBTSXpORE1pSUdadmJuUXRjMmw2WlQwaU1UQWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGliV2xrWkd4bElpQm1iMjUwTFdaaGJXbHNlVDBpWm5WMGRYSmhJajQ4ZEhOd1lXNCtQR0Z1YVcxaGRHVWdZWFIwY21saWRYUmxUbUZ0WlQwaWVDSWdabkp2YlQwaU5UQWlJSFJ2UFNJdE1qYzFJaUJrZFhJOUlqRXdjeUlnY21Wd1pXRjBRMjkxYm5ROUltbHVaR1ZtYVc1cGRHVWlJQzgrTUhoaVpXRXdaVEV4TWpneVpUSmlZalU0T1ROaVpXTmxNVEV3WTJZeE9UazFNREZsT0RjeVltRmtQQzkwYzNCaGJqNDhMM1JsZUhRK1BIUmxlSFFnZUQwaU1qTTFJaUI1UFNJeE5DNDFJaUJtYjI1MExYTnBlbVU5SWpFeUlpQm1hV3hzUFNKWGFHbDBaU0lnZEdWNGRDMWhibU5vYjNJOUltVnVaQ0lnWm05dWRDMW1ZVzFwYkhrOUltWjFkSFZ5WVNJK1UzUmxiVG9nTFRFdU56VTVNakZsTVRNOEwzUmxlSFErUEM5emRtYysifQ== \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJCRUFORVRIIn0sIHsgInRyYWl0X3R5cGUiOiAiVG9rZW4gQWRkcmVzcyIsICJ2YWx1ZSI6ICIweGJlYTBlMTEyODJlMmJiNTg5M2JlY2UxMTBjZjE5OTUwMWU4NzJiYWQifSwgeyAidHJhaXRfdHlwZSI6ICJJZCIsICJ2YWx1ZSI6ICIweGJlYTBlMTEyODJlMmJiNTg5M2JlY2UxMTBjZjE5OTUwMWU4NzJiYWRmZmZmZmZmZmZmZmZmMDAwMDAwMDAwMDIifSwgeyAidHJhaXRfdHlwZSI6ICJzdGVtIiwgImRpc3BsYXlfdHlwZSI6ICJudW1iZXIiLCAidmFsdWUiOiAtMTc1OTIxODYwNDQ0MTR9LCB7ICJ0cmFpdF90eXBlIjogImluaXRhbCBzdGFsayBwZXIgQkRWIiwgImRpc3BsYXlfdHlwZSI6ICJudW1iZXIiLCAidmFsdWUiOiAxMDAwMH0sIHsgInRyYWl0X3R5cGUiOiAiZ3Jvd24gc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMTc1OTIxODYwNDg0MTh9LCB7ICJ0cmFpdF90eXBlIjogInN0YWxrIGdyb3duIHBlciBCRFYgcGVyIHNlYXNvbiIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogNDAwMDAwMCwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OEwyYytQR2NnYVdROUluQmhjblJwWVd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOd1lYSjBhV0ZzVEdWaFpsSnZkeUlnZUQwaUxUTTFJaUI1UFNJd0lpQm1hV3hzUFNJalFUaERPRE5CSWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4TDJjK1BHY2dhV1E5SW14bFlXWWlQanh3WVhSb0lHUTlJazB4TnpFdU9EZzBJREV4T0M0NU9ETmhOQzQ1TXpJZ05DNDVNeklnTUNBd0lERXRNUzR3TVRnZ01pNDJNRFlnTkM0M01UVWdOQzQzTVRVZ01DQXdJREV0TVM0NE56Z2dNUzQwTXpsakxTNDBOalV1TVRrMUxURXVOek0xTGpjeU55MHlMak0yTkM0eE56WXRMakkwTmlBekxqSTVPQzB4TGpVNU15QTJMalV4TWkweUxqSTFNeUEzTGprMU5HRTBMalV6TWlBMExqVXpNaUF3SURBZ01TMHVNekV6TFM0NU16TmpMUzR5TVRFdExqazNOUzB1TURNNExURXVOell6TGpBM09DMHlMakk1TlM0eU1ESXRMamt5TVM0ek5UTXRNUzQyTVRJdU5EWTNMVEl1TVRRdE1TNHhOemN1TmprMExUSXVOalF5TGpVMk9TMHpMalUxT0MwdU1qY3lMUzQzT1RZdExqY3pNaTB4TGpBNE15MHhMamt5TVMwdU56UXpMVE11TURNMExqUTVPQzR3TVRFZ01TNDVNemt1TVRBNUlETXVNalEzSURFdU1UWTNZVFV1TVRNZ05TNHhNeUF3SURBZ01TQXhMakl4SURFdU5ERXpZeTR4TlRrdExqYzBMakU1T1MwdU9UVTRMakl6T0MweExqRTNPUzR5TURrdE1TNHlNVE11TXpJeUxURXVPRGN5TGpJM05DMHlMamN5TkdFM0xqY3pJRGN1TnpNZ01DQXdJREF0TGprd09DMHpMakUzTjJNdExqYzNNaTQwTVRVdE1TNDNPRGt1TVRrMkxUSXVNemM0TFM0ek1EUXRMak16T1MwdU1qZzNMUzQxTlRZdExqWTRNaTB1TnpZMExURXVOamt5WVRFeUxqY3pPU0F4TWk0M016a2dNQ0F3SURFdExqRTNOaTB6TGprd09XTXVOemc1TGpZd015QXhMalEzSURFdU1ERTVJREV1T1RNM0lERXVNamd6TGprME5DNDFNellnTVM0ek5EUXVOak01SURFdU56WXhJREV1TVRZM0xqRTFNaTR4T1RNdU5qUTVMamcwTWk0MU9EWWdNUzQzTlRFdExqQXhNUzR4TnpJdExqQTFNeTQzT1RVdExqUTJOQ0F4TGpJNU0yRTJMamd6SURZdU9ETWdNQ0F3SURFZ01TNHpPRFFnTWk0eU1qZGpMakUwTGpNMk9DNHlOREl1TnpRMExqTXhNU0F4TGpFMUxqRXdOeTB1TWpBM0xqSTJNUzB1TkRNNUxqVXhNUzB1TnpJeUxqUTFNeTB1TlRFekxqZzNMUzQ1T1RJZ01TNDJNRFF0TVM0eU9EUXVOamd6TFM0eU56SWdNUzR5T0MwdU1qUTVJREV1TnpJekxTNHlNelJoTlM0ek1ESWdOUzR6TURJZ01DQXdJREVnTVM0ME9EWXVNamN6V2lJdlBqd3ZaejQ4WnlCcFpEMGljMmxzYnlJK1BIQmhkR2dnWkQwaVRUVTNMakV3T0NBM01TNHlPV011TVRnNExURXhMalkxTXkweE1pNHdNUzB5TVM0ek1ETXRNamN1TWpRekxUSXhMalUxTWkweE5TNHlNelF0TGpJMUxUSTNMamN6TmlBNExqazVOUzB5Tnk0NU1qTWdNakF1TmpRNUxTNHhPRGNnTVRFdU5qVTBJREV5TGpBeElESXhMak13TkNBeU55NHlORFFnTWpFdU5UVXpJREUxTGpJek15NHlOU0F5Tnk0M016VXRPQzQ1T1RVZ01qY3VPVEl5TFRJd0xqWTFXaUlnWm1sc2JEMGlJelkyTmlJdlBqeHdZWFJvSUdROUlrMHVORFkwSURFNUxqVTBOR011TmprNUlERTJMalU0TlNBeExqUWdNek11TVRZNUlESXVNRGs0SURRNUxqYzFNaTR3TWpFZ01pNHpPREV1TkRnZ05DNHlOemd1T0RneklEVXVOVE01TGpJM055NDROaTQzTkRFZ01pNHlOelVnTVM0M056Z2dNeTQ0TmpjdU5EazBMamMxT1NBeExqSXhNaUF4TGpjZ015NHdNRElnTXk0ek16SWdNUzQzTXprZ01TNDFPRFlnTXk0ek5TQXpMakExTmlBMUxqY3pNaUEwTGpNNU9DQXpMakk1TXlBeExqZzFOU0EyTGpFMU1TQXlMak01TmlBNExqYzVNU0F5TGpnNU5pQXhMamcxTlM0ek5TQTFMakUwT1M0NU5EZ2dPUzQwT0RndU5UVTJZVE15TGpjd055QXpNaTQzTURjZ01DQXdJREFnT1M0ek1UVXRNaTR5T0Rkak1TNDROakl0TGpjMU9TQTBMalkwTWkweExqa3hOeUEzTGpZek15MDBMalFnTVM0ek5EZ3RNUzR4TWlBekxqUTBPQzB5TGpnNU55QTFMakU1TnkwMUxqazFZVEl3TGpFeE5DQXlNQzR4TVRRZ01DQXdJREFnTWk0eU5TMDFMams1T0dNdU1qRXRNVGN1TlRVeUxqUXlMVE0xTGpFd05DNDJNekl0TlRJdU5qVTNiQzAxTmk0NExqazFNbWd1TURBeFdpSWdabWxzYkQwaUkwSXpRak5DTXlJdlBqeHdZWFJvSUdROUlrMDFOeTQwT0NBeE9TNDBPREpETlRjdU5qUTFJRGt1TWpRZ05EUXVPVGM0TGpjeU55QXlPUzR4T0RjdU5EWTRJREV6TGpNNU55NHlNUzQwTmpNZ09DNHpNRE11TWprNElERTRMalUwTmk0eE16UWdNamd1TnpnNElERXlMamdnTXpjdU15QXlPQzQxT1RFZ016Y3VOVFpqTVRVdU56a3VNalU0SURJNExqY3lOQzAzTGpnek5TQXlPQzQ0T0RrdE1UZ3VNRGM0V2lJZ1ptbHNiRDBpSTBORFF5SXZQanh3WVhSb0lHUTlJazB6TUM0ek1UUWdOeTR4TXpkakxqQXdPUzB1TlRZeExTNDJPQzB4TGpBeU9DMHhMalV6T0MweExqQTBNaTB1T0RVNUxTNHdNVFF0TVM0MU5qSXVORE10TVM0MU56RXVPVGt4TFM0d01TNDFOakl1TmpnZ01TNHdNamdnTVM0MU16Z2dNUzR3TkRJdU9EVTVMakF4TlNBeExqVTJNaTB1TkRNZ01TNDFOeTB1T1RsYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFRZdU5ERTBJREk0TGpnNVlURTFMamMzTnlBeE5TNDNOemNnTUNBd0lERXRNaTR3T1RNdE1pNHhORFpqTFM0NE5UWXRNUzR3TmpNdE1pNDBOVE10TXk0d09UTXRNaTQ1TnpVdE5pNHhNVEpoTVRFdU56WTFJREV4TGpjMk5TQXdJREFnTVMwdU1Ea3pMVE11TXpBM2JESTFMalF6TFRrdU9UYzJZeTR3TkRNdU1UUXlMakU0T0M0MU5UVXVOakEwTGpnMk9DNDBOaTR6TkRZdU9UUTNMak0wSURFdU1EZzJMak16TkV3MkxqUXhNeUF5T0M0NE9EaDJMakF3TWxvaUlHWnBiR3c5SWlORk5rVTJSVFlpTHo0OGNHRjBhQ0J2Y0dGamFYUjVQU0l1TXpNaUlHUTlJazB4TGpRM055QXhOaTR3TWpsakxqSTFMUzQ1TXpFdU56QTJMVEl1TWpVNElERXVOVGN0TXk0Mk9UVXVOalUxTFRFdU1Ea3lJREV1TWpreUxURXVPREkxSURFdU56WXRNaTR6TlRndU5UZzBMUzQyTmpVZ01TNDNOell0TVM0NU16UWdNeTQyTnprdE15NHlPU0F5TGprMU15MHlMakV3TlNBMUxqWTVOaTB6TGpBMUlEY3VOekl6TFRNdU56TmhNemN1TXpVZ016Y3VNelVnTUNBd0lERWdOaTQwT0RVdE1TNDFORGRzTlM0eU5ESWdOQzR6TVRaaE1TNDBPQ0F4TGpRNElEQWdNQ0F3TFRFdU1qRTBMamsyTjB3eExqUTRJREUyTGpBemFDMHVNREF5V2lJZ1ptbHNiRDBpSXprNU9TSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNDBOQ0lnWkQwaVRURXVPREVnTWpZdU5UTXlZeTR5TURZdU5EazBMalE0TkNBeExqQTFMamcySURFdU5qTmhNVEF1TWpZMklERXdMakkyTmlBd0lEQWdNQ0F5TGpJM09DQXlMalE0Tmt3MkxqVTFNaUEzT0M0eU1tRXhOeTR5TnpJZ01UY3VNamN5SURBZ01DQXhMVE10Tnk0ME1UTk1NUzQ0TVNBeU5pNDFNekphSWlCbWFXeHNQU0lqUlRaRk5rVTJJaTgrUEhCaGRHZ2daRDBpYlRNekxqQTVNaUEwT1M0ME5ERXROaTR6T0RFZ01UVXVNakV4Y3kwMkxqQTNPQzB4TVM0eE5Ua2dOaTR6T0RFdE1UVXVNakZhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEhCaGRHZ2daRDBpYlRJMkxqY3lOU0EyTkM0NE5UZ3RMakE1TVMwdU1UYzFZeTB1TURJMkxTNHdORGt0TWk0Mk16UXROQzQ1TWpNdExqZzJOeTA1TGpNM0lERXVNRFUzTFRJdU56RTNJRE11TlRFNExUUXVOekkxSURjdU15MDFMamswTm13dU1UZzNMUzR3TmpFdE5pNDFNeUF4TlM0MU5USmFiVFl1TWpFeUxURTFMakkyT0dNdE15NDJNakVnTVM0eU1UY3ROUzQ1T1RFZ015NHhOamd0Tnk0d01qSWdOUzQzT1RndE1TNDFNemdnTXk0NU1EZ3VNelUxSURndU1UWTJMamM0T0NBNUxqQTFOR3cyTGpJek5DMHhOQzQ0TlRKYVRUSTRMakE1TXlBMk15NDNNemRzTkM0ME9EUXRNVEF1T0Rkek55NHpOalVnTmk0ek16Y3ROQzQwT0RRZ01UQXVPRGRhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEM5blBqeG5JR2xrUFNKQ1JVRk9JajQ4Y21WamRDQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnM0lERXVNalkxTFRNdU5UQTBJRGt1TXpaVExqSTVPQ0F6TGprNU9TQTNMalk0TnlBeExqSTJObHB0TFRJdU5qa3hJRGd1TnpnZ01pNDBOakl0Tmk0Mk9URnpOQzQxTXpnZ015NDJOeTB5TGpRMk1pQTJMalk1TVZvaUlHWnBiR3c5SWlObVptWWlMejQ4TDJjK1BHY2dhV1E5SWtKRlFVNHpRMUpXSWo0OGNtVmpkQ0I1UFNJdU5TSWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE55QXhMamMyTkMwekxqVXdOQ0E1TGpNMlV5NHlPVGdnTkM0ME9Ua2dOeTQyT0RjZ01TNDNOalZhSWlCbWFXeHNQU0lqWm1abUlpOCtQSEJoZEdnZ1pEMGlUVGd1TVRNeUlEZ3VNRGM0WXkwdU5EWTJMalkwTFRFdU1qazNJREV1TXpJekxUSXVOamsxSURFdU9Ua3liREl1TVRJMkxUVXVOemMzWXk0d09Ea3VNRGt1TVRrekxqSXdOQzR6TGpNek9DNHpNRE11TXpjMUxqWXlOUzQ0T1RFdU56UTBJREV1TkRnMExqRXhOeTQxT0RNdU1EUWdNUzR5TlRNdExqUTNOU0F4TGprMk0xb2lJR1pwYkd3OUluVnliQ2dqWVNraUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMWGRwWkhSb1BTSXVOU0l2UGp4a1pXWnpQanhzYVc1bFlYSkhjbUZrYVdWdWRDQnBaRDBpWVNJZ2VERTlJall1T1RVaUlIa3hQU0l6TGpnMU15SWdlREk5SWpZdU9UVWlJSGt5UFNJeE1DNDFORFFpSUdkeVlXUnBaVzUwVlc1cGRITTlJblZ6WlhKVGNHRmpaVTl1VlhObElqNDhjM1J2Y0NCemRHOXdMV052Ykc5eVBTSWpPREl3TWpBeUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU1UZ3lJaUJ6ZEc5d0xXTnZiRzl5UFNJalJqY3hSVEExSWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TlRFMklpQnpkRzl3TFdOdmJHOXlQU0lqUmpCR05UQTNJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOek0wSWlCemRHOXdMV052Ykc5eVBTSWpPRFZEUkRjMUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeElpQnpkRzl3TFdOdmJHOXlQU0lqTURJNVJFWkNJaTgrUEM5c2FXNWxZWEpIY21Ga2FXVnVkRDQ4TDJSbFpuTStQQzluUGp4bklHbGtQU0oxY2tKRlFVNGlQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RjZ01TNHlOalV0TXk0MU1EUWdPUzR6TmxNdU1qazRJRE11T1RrNUlEY3VOamczSURFdU1qWTJXbTB0TWk0Mk9URWdPQzQzT0NBeUxqUTJNaTAyTGpZNU1YTTBMalV6T0NBekxqWTNMVEl1TkRZeUlEWXVOamt4V2lJZ1ptbHNiRDBpSTJabVppSXZQand2Wno0OFp5QnBaRDBpUWtWQlRrVlVTQ0krUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE5DQXhMakkyTlMwekxqVXdOU0E1TGpNMll5NHdNRE1nTUMwekxqZzROQzAyTGpZeU5TQXpMalV3TlMwNUxqTTJXaUlnWm1sc2JEMGlJMlptWmlJdlBqeHdZWFJvSUdROUlrMDRMamsxTWlBMkxqazRObUV1TURZekxqQTJNeUF3SURBZ01TMHVNREl5TGpBd00yTXRMamN4TGpFekxURXVOREkwTGpJMU5TMHlMakV6TkM0ek9ERXRMakk0TVM0d05USXRMalUyTlM0eE1ETXRMamcwTmk0eE5USmhMakF6Tmk0d016WWdNQ0F3SURFdExqQXlOaUF3YkRJdU1UUXROUzQyTWpVdU1EQTBMUzR3TUROakxqSTVOeUF4TGpjd01pNDFPU0F6TGpNNU5DNDRPRFFnTlM0d09USmFiUzB1TVRnM0xqUTNPR010TVM0eU5qWXVPRFU1TFRJdU5UTXhJREV1TnpJeExUTXVPQ0F5TGpVNGJDNDNPREV0TWk0d05UUmpMakF3Tnk0d01EUXVNREV6SURBZ0xqQXlNeUF3SUM0M05Ua3RMakV6TWlBeExqVXhOQzB1TWpZNElESXVNamN0TGpSc0xqWTVOeTB1TVRJMkxqQXpMUzR3TURaakxTNHdNRFF1TURBeklEQWdMakF3TmlBd0lDNHdNRFphSWlCbWFXeHNQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0oxY2tKRlFVNUZWRWdpUGp4eVpXTjBJSGRwWkhSb1BTSXhNaUlnYUdWcFoyaDBQU0l4TWlJZ2NuZzlJallpSUdacGJHdzlJaU0zUmpVMU16TWlMejQ4Y0dGMGFDQmtQU0p0Tnk0Mk9EUWdNUzR5TmpVdE15NDFNRFVnT1M0ek5tTXVNREF6SURBdE15NDRPRFF0Tmk0Mk1qVWdNeTQxTURVdE9TNHpObG9pSUdacGJHdzlJaU5tWm1ZaUx6NDhjR0YwYUNCa1BTSk5PQzQ1TlRJZ05pNDVPRFpoTGpBMk15NHdOak1nTUNBd0lERXRMakF5TWk0d01ETmpMUzQzTVM0eE15MHhMalF5TkM0eU5UVXRNaTR4TXpRdU16Z3hMUzR5T0RFdU1EVXlMUzQxTmpVdU1UQXpMUzQ0TkRZdU1UVXlZUzR3TXpZdU1ETTJJREFnTUNBeExTNHdNallnTUd3eUxqRTBMVFV1TmpJMUxqQXdOQzB1TURBell5NHlPVGNnTVM0M01ESXVOVGtnTXk0ek9UUXVPRGcwSURVdU1Ea3lXbTB0TGpFNE55NDBOemhqTFRFdU1qWTJMamcxT1MweUxqVXpNU0F4TGpjeU1TMHpMamdnTWk0MU9Hd3VOemd4TFRJdU1EVTBZeTR3TURjdU1EQTBMakF4TXlBd0lDNHdNak1nTUNBdU56VTVMUzR4TXpJZ01TNDFNVFF0TGpJMk9DQXlMakkzTFM0MGJDNDJPVGN0TGpFeU5pNHdNeTB1TURBMll5MHVNREEwTGpBd015QXdJQzR3TURZZ01DQXVNREEyV2lJZ1ptbHNiRDBpSXpBd01DSXZQand2Wno0OFp5QnBaRDBpYkdWaFpsSnZkeUkrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTUNJZ2VUMGlNQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweE1pSWdlVDBpTFRjaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXRNalFpSUhrOUlpMHhOQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkwek5pSWdlVDBpTFRJeElpOCtQQzluUGp3dlpHVm1jejQ4Y21WamRDQjNhV1IwYUQwaU1qVTFJaUJvWldsbmFIUTlJak0xTUNJZ2NuZzlJakV3SWlCbWFXeHNQU0lqTWpVek16STJJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYzJsc2J5SWdlRDBpT1RraUlIazlJalUxSWk4K1BHY2dhV1E5SW1Gc2JGQnNiM1FpSUdOc2FYQXRjR0YwYUQwaWRYSnNLQ05pYjNKa1pYSk5ZWE5yS1NJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpuVnNiRXhsWVdaUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWkweE5qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVEUyTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTm1kV3hzVEdWaFpsQnNiM1FpSUhnOUlqQWlJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l4TXpnaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXRNVEkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJdE9EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVGcwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTUNJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJdE5EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0l0TmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM05wYkc4aUlIZzlJalEzSWlCNVBTSTFOU0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpjcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXpOaUlnTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlObWRXeHNUR1ZoWmxCc2IzUWlJSGc5SWpFek9DSWdlVDBpTXpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpablZzYkV4bFlXWlFiRzkwSWlCNFBTSXROamtpSUhrOUlqYzJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTmpraUlIazlJamMySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTUNJZ2VUMGlNVEUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWm5Wc2JFeGxZV1pRYkc5MElpQjRQU0kyT1NJZ2VUMGlNVFUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJeE5UWWlJQzgrUEM5blBqeHlaV04wSUhnOUlqQWlJSGs5SWpBaUlIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNakFpSUhKNFBTSTFJaUJtYVd4c1BTSWpNalF5TkRJMElpOCtQSFJsZUhRZ2VEMGlNVEFpSUhrOUlqRTBMalVpSUdadmJuUXRjMmw2WlQwaU1USWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGljM1JoY25RaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQa0pGUVU1RlZFZ2dSR1Z3YjNOcGREd3ZkR1Y0ZEQ0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOQ1JVRk9SVlJJSWlCNFBTSXlOREFpSUhrOUlqUWlJQzgrUEhKbFkzUWdlRDBpTUNJZ2VUMGlNek13SWlCM2FXUjBhRDBpTWpVMUlpQm9aV2xuYUhROUlqSXdJaUJ5ZUQwaU5TSWdabWxzYkQwaUl6STBNalF5TkNJdlBqeDBaWGgwSUhnOUlqRXlOeUlnZVQwaU16UXpJaUJtYjI1MExYTnBlbVU5SWpFd0lpQm1hV3hzUFNKWGFHbDBaU0lnZEdWNGRDMWhibU5vYjNJOUltMXBaR1JzWlNJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStQSFJ6Y0dGdVBqeGhibWx0WVhSbElHRjBkSEpwWW5WMFpVNWhiV1U5SW5naUlHWnliMjA5SWpNM05TSWdkRzg5SWpVd0lpQmtkWEk5SWpFd2N5SWdjbVZ3WldGMFEyOTFiblE5SW1sdVpHVm1hVzVwZEdVaUlDOCtNSGhpWldFd1pURXhNamd5WlRKaVlqVTRPVE5pWldObE1URXdZMll4T1RrMU1ERmxPRGN5WW1Ga1BDOTBjM0JoYmo0OEwzUmxlSFErUEhSbGVIUWdlRDBpTVRJM0lpQjVQU0l6TkRNaUlHWnZiblF0YzJsNlpUMGlNVEFpSUdacGJHdzlJbGRvYVhSbElpQjBaWGgwTFdGdVkyaHZjajBpYldsa1pHeGxJaUJtYjI1MExXWmhiV2xzZVQwaVpuVjBkWEpoSWo0OGRITndZVzQrUEdGdWFXMWhkR1VnWVhSMGNtbGlkWFJsVG1GdFpUMGllQ0lnWm5KdmJUMGlOVEFpSUhSdlBTSXRNamMxSWlCa2RYSTlJakV3Y3lJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUM4K01IaGlaV0V3WlRFeE1qZ3laVEppWWpVNE9UTmlaV05sTVRFd1kyWXhPVGsxTURGbE9EY3lZbUZrUEM5MGMzQmhiajQ4TDNSbGVIUStQSFJsZUhRZ2VEMGlNak0xSWlCNVBTSXhOQzQxSWlCbWIyNTBMWE5wZW1VOUlqRXlJaUJtYVd4c1BTSlhhR2wwWlNJZ2RHVjRkQzFoYm1Ob2IzSTlJbVZ1WkNJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStVM1JsYlRvZ0xURXVOelU1TWpGbE1UTThMM1JsZUhRK1BDOXpkbWMrIn0= \ No newline at end of file diff --git a/protocol/test/data/base64EncodedImageUrBean.txt b/protocol/test/data/base64EncodedImageUrBean.txt index 9d20629db0..feb8b02e1f 100644 --- a/protocol/test/data/base64EncodedImageUrBean.txt +++ b/protocol/test/data/base64EncodedImageUrBean.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IHVyQkVBTlxuVG9rZW4gQWRkcmVzczogMHgxYmVhMDA1MGU2M2UwNWZiYjVkOGJhMmYxMGNmNTgwMGI2MjI0NDQ5XG5JZDogMHgxYmVhMDA1MGU2M2UwNWZiYjVkOGJhMmYxMGNmNTgwMGI2MjI0NDQ5MDAwMDAwMDAwMDAwMDAwMDAwMDAwNDAwXG5zdGVtOiAxMDI0XG5pbml0YWwgc3RhbGsgcGVyIEJEVjogMTAwMDBcbmdyb3duIHN0YWxrIHBlciBCRFY6IDk3OFxuc3RhbGsgZ3Jvd24gcGVyIEJEViBwZXIgc2Vhc29uOiAyMDAwMDAwXG5cbkRJU0NMQUlNRVI6IER1ZSBkaWxpZ2VuY2UgaXMgaW1wZXJhdGl2ZSB3aGVuIGFzc2Vzc2luZyB0aGlzIE5GVC4gT3BlbnNlYSBhbmQgb3RoZXIgTkZUIG1hcmtldHBsYWNlcyBjYWNoZSB0aGUgc3ZnIG91dHB1dCBhbmQgdGh1cywgbWF5IHJlcXVpcmUgdGhlIHVzZXIgdG8gcmVmcmVzaCB0aGUgbWV0YWRhdGEgdG8gcHJvcGVybHkgc2hvdyB0aGUgY29ycmVjdCB2YWx1ZXMuIiwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmxKdmR5SWdlRDBpTFRNMUlpQjVQU0l3SWlCbWFXeHNQU0lqUVRoRE9ETkJJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhMMmMrUEdjZ2FXUTlJbXhsWVdZaVBqeHdZWFJvSUdROUlrMHhOekV1T0RnMElERXhPQzQ1T0ROaE5DNDVNeklnTkM0NU16SWdNQ0F3SURFdE1TNHdNVGdnTWk0Mk1EWWdOQzQzTVRVZ05DNDNNVFVnTUNBd0lERXRNUzQ0TnpnZ01TNDBNemxqTFM0ME5qVXVNVGsxTFRFdU56TTFMamN5TnkweUxqTTJOQzR4TnpZdExqSTBOaUF6TGpJNU9DMHhMalU1TXlBMkxqVXhNaTB5TGpJMU15QTNMamsxTkdFMExqVXpNaUEwTGpVek1pQXdJREFnTVMwdU16RXpMUzQ1TXpOakxTNHlNVEV0TGprM05TMHVNRE00TFRFdU56WXpMakEzT0MweUxqSTVOUzR5TURJdExqa3lNUzR6TlRNdE1TNDJNVEl1TkRZM0xUSXVNVFF0TVM0eE56Y3VOamswTFRJdU5qUXlMalUyT1MwekxqVTFPQzB1TWpjeUxTNDNPVFl0TGpjek1pMHhMakE0TXkweExqa3lNUzB1TnpRekxUTXVNRE0wTGpRNU9DNHdNVEVnTVM0NU16a3VNVEE1SURNdU1qUTNJREV1TVRZM1lUVXVNVE1nTlM0eE15QXdJREFnTVNBeExqSXhJREV1TkRFell5NHhOVGt0TGpjMExqRTVPUzB1T1RVNExqSXpPQzB4TGpFM09TNHlNRGt0TVM0eU1UTXVNekl5TFRFdU9EY3lMakkzTkMweUxqY3lOR0UzTGpjeklEY3VOek1nTUNBd0lEQXRMamt3T0MwekxqRTNOMk10TGpjM01pNDBNVFV0TVM0M09Ea3VNVGsyTFRJdU16YzRMUzR6TURRdExqTXpPUzB1TWpnM0xTNDFOVFl0TGpZNE1pMHVOelkwTFRFdU5qa3lZVEV5TGpjek9TQXhNaTQzTXprZ01DQXdJREV0TGpFM05pMHpMamt3T1dNdU56ZzVMall3TXlBeExqUTNJREV1TURFNUlERXVPVE0zSURFdU1qZ3pMamswTkM0MU16WWdNUzR6TkRRdU5qTTVJREV1TnpZeElERXVNVFkzTGpFMU1pNHhPVE11TmpRNUxqZzBNaTQxT0RZZ01TNDNOVEV0TGpBeE1TNHhOekl0TGpBMU15NDNPVFV0TGpRMk5DQXhMakk1TTJFMkxqZ3pJRFl1T0RNZ01DQXdJREVnTVM0ek9EUWdNaTR5TWpkakxqRTBMak0yT0M0eU5ESXVOelEwTGpNeE1TQXhMakUxTGpFd055MHVNakEzTGpJMk1TMHVORE01TGpVeE1TMHVOekl5TGpRMU15MHVOVEV6TGpnM0xTNDVPVElnTVM0Mk1EUXRNUzR5T0RRdU5qZ3pMUzR5TnpJZ01TNHlPQzB1TWpRNUlERXVOekl6TFM0eU16UmhOUzR6TURJZ05TNHpNRElnTUNBd0lERWdNUzQwT0RZdU1qY3pXaUl2UGp3dlp6NDhaeUJwWkQwaWMybHNieUkrUEhCaGRHZ2daRDBpVFRVM0xqRXdPQ0EzTVM0eU9XTXVNVGc0TFRFeExqWTFNeTB4TWk0d01TMHlNUzR6TURNdE1qY3VNalF6TFRJeExqVTFNaTB4TlM0eU16UXRMakkxTFRJM0xqY3pOaUE0TGprNU5TMHlOeTQ1TWpNZ01qQXVOalE1TFM0eE9EY2dNVEV1TmpVMElERXlMakF4SURJeExqTXdOQ0F5Tnk0eU5EUWdNakV1TlRVeklERTFMakl6TXk0eU5TQXlOeTQzTXpVdE9DNDVPVFVnTWpjdU9USXlMVEl3TGpZMVdpSWdabWxzYkQwaUl6WTJOaUl2UGp4d1lYUm9JR1E5SWswdU5EWTBJREU1TGpVME5HTXVOams1SURFMkxqVTROU0F4TGpRZ016TXVNVFk1SURJdU1EazRJRFE1TGpjMU1pNHdNakVnTWk0ek9ERXVORGdnTkM0eU56Z3VPRGd6SURVdU5UTTVMakkzTnk0NE5pNDNOREVnTWk0eU56VWdNUzQzTnpnZ015NDROamN1TkRrMExqYzFPU0F4TGpJeE1pQXhMamNnTXk0d01ESWdNeTR6TXpJZ01TNDNNemtnTVM0MU9EWWdNeTR6TlNBekxqQTFOaUExTGpjek1pQTBMak01T0NBekxqSTVNeUF4TGpnMU5TQTJMakUxTVNBeUxqTTVOaUE0TGpjNU1TQXlMamc1TmlBeExqZzFOUzR6TlNBMUxqRTBPUzQ1TkRnZ09TNDBPRGd1TlRVMllUTXlMamN3TnlBek1pNDNNRGNnTUNBd0lEQWdPUzR6TVRVdE1pNHlPRGRqTVM0NE5qSXRMamMxT1NBMExqWTBNaTB4TGpreE55QTNMall6TXkwMExqUWdNUzR6TkRndE1TNHhNaUF6TGpRME9DMHlMamc1TnlBMUxqRTVOeTAxTGprMVlUSXdMakV4TkNBeU1DNHhNVFFnTUNBd0lEQWdNaTR5TlMwMUxqazVPR011TWpFdE1UY3VOVFV5TGpReUxUTTFMakV3TkM0Mk16SXROVEl1TmpVM2JDMDFOaTQ0TGprMU1tZ3VNREF4V2lJZ1ptbHNiRDBpSTBJelFqTkNNeUl2UGp4d1lYUm9JR1E5SWswMU55NDBPQ0F4T1M0ME9ESkROVGN1TmpRMUlEa3VNalFnTkRRdU9UYzRMamN5TnlBeU9TNHhPRGN1TkRZNElERXpMak01Tnk0eU1TNDBOak1nT0M0ek1ETXVNams0SURFNExqVTBOaTR4TXpRZ01qZ3VOemc0SURFeUxqZ2dNemN1TXlBeU9DNDFPVEVnTXpjdU5UWmpNVFV1TnprdU1qVTRJREk0TGpjeU5DMDNMamd6TlNBeU9DNDRPRGt0TVRndU1EYzRXaUlnWm1sc2JEMGlJME5EUXlJdlBqeHdZWFJvSUdROUlrMHpNQzR6TVRRZ055NHhNemRqTGpBd09TMHVOVFl4TFM0Mk9DMHhMakF5T0MweExqVXpPQzB4TGpBME1pMHVPRFU1TFM0d01UUXRNUzQxTmpJdU5ETXRNUzQxTnpFdU9Ua3hMUzR3TVM0MU5qSXVOamdnTVM0d01qZ2dNUzQxTXpnZ01TNHdOREl1T0RVNUxqQXhOU0F4TGpVMk1pMHVORE1nTVM0MU55MHVPVGxhSWlCbWFXeHNQU0lqTmpZMklpOCtQSEJoZEdnZ1pEMGlUVFl1TkRFMElESTRMamc1WVRFMUxqYzNOeUF4TlM0M056Y2dNQ0F3SURFdE1pNHdPVE10TWk0eE5EWmpMUzQ0TlRZdE1TNHdOak10TWk0ME5UTXRNeTR3T1RNdE1pNDVOelV0Tmk0eE1USmhNVEV1TnpZMUlERXhMamMyTlNBd0lEQWdNUzB1TURrekxUTXVNekEzYkRJMUxqUXpMVGt1T1RjMll5NHdORE11TVRReUxqRTRPQzQxTlRVdU5qQTBMamcyT0M0ME5pNHpORFl1T1RRM0xqTTBJREV1TURnMkxqTXpORXcyTGpReE15QXlPQzQ0T0RoMkxqQXdNbG9pSUdacGJHdzlJaU5GTmtVMlJUWWlMejQ4Y0dGMGFDQnZjR0ZqYVhSNVBTSXVNek1pSUdROUlrMHhMalEzTnlBeE5pNHdNamxqTGpJMUxTNDVNekV1TnpBMkxUSXVNalU0SURFdU5UY3RNeTQyT1RVdU5qVTFMVEV1TURreUlERXVNamt5TFRFdU9ESTFJREV1TnpZdE1pNHpOVGd1TlRnMExTNDJOalVnTVM0M056WXRNUzQ1TXpRZ015NDJOemt0TXk0eU9TQXlMamsxTXkweUxqRXdOU0ExTGpZNU5pMHpMakExSURjdU56SXpMVE11TnpOaE16Y3VNelVnTXpjdU16VWdNQ0F3SURFZ05pNDBPRFV0TVM0MU5EZHNOUzR5TkRJZ05DNHpNVFpoTVM0ME9DQXhMalE0SURBZ01DQXdMVEV1TWpFMExqazJOMHd4TGpRNElERTJMakF6YUMwdU1EQXlXaUlnWm1sc2JEMGlJems1T1NJdlBqeHdZWFJvSUc5d1lXTnBkSGs5SWk0ME5DSWdaRDBpVFRFdU9ERWdNall1TlRNeVl5NHlNRFl1TkRrMExqUTROQ0F4TGpBMUxqZzJJREV1TmpOaE1UQXVNalkySURFd0xqSTJOaUF3SURBZ01DQXlMakkzT0NBeUxqUTROa3cyTGpVMU1pQTNPQzR5TW1FeE55NHlOeklnTVRjdU1qY3lJREFnTUNBeExUTXROeTQwTVROTU1TNDRNU0F5Tmk0MU16SmFJaUJtYVd4c1BTSWpSVFpGTmtVMklpOCtQSEJoZEdnZ1pEMGliVE16TGpBNU1pQTBPUzQwTkRFdE5pNHpPREVnTVRVdU1qRXhjeTAyTGpBM09DMHhNUzR4TlRrZ05pNHpPREV0TVRVdU1qRmFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQSEJoZEdnZ1pEMGliVEkyTGpjeU5TQTJOQzQ0TlRndExqQTVNUzB1TVRjMVl5MHVNREkyTFM0d05Ea3RNaTQyTXpRdE5DNDVNak10TGpnMk55MDVMak0zSURFdU1EVTNMVEl1TnpFM0lETXVOVEU0TFRRdU56STFJRGN1TXkwMUxqazBObXd1TVRnM0xTNHdOakV0Tmk0MU15QXhOUzQxTlRKYWJUWXVNakV5TFRFMUxqSTJPR010TXk0Mk1qRWdNUzR5TVRjdE5TNDVPVEVnTXk0eE5qZ3ROeTR3TWpJZ05TNDNPVGd0TVM0MU16Z2dNeTQ1TURndU16VTFJRGd1TVRZMkxqYzRPQ0E1TGpBMU5HdzJMakl6TkMweE5DNDROVEphVFRJNExqQTVNeUEyTXk0M016ZHNOQzQwT0RRdE1UQXVPRGR6Tnk0ek5qVWdOaTR6TXpjdE5DNDBPRFFnTVRBdU9EZGFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQQzluUGp4bklHbGtQU0pDUlVGT0lqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU1qWTFMVE11TlRBMElEa3VNelpUTGpJNU9DQXpMams1T1NBM0xqWTROeUF4TGpJMk5scHRMVEl1TmpreElEZ3VOemdnTWk0ME5qSXROaTQyT1RGek5DNDFNemdnTXk0Mk55MHlMalEyTWlBMkxqWTVNVm9pSUdacGJHdzlJaU5tWm1ZaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0elExSldJajQ4Y21WamRDQjVQU0l1TlNJZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TnlBeExqYzJOQzB6TGpVd05DQTVMak0yVXk0eU9UZ2dOQzQwT1RrZ055NDJPRGNnTVM0M05qVmFJaUJtYVd4c1BTSWpabVptSWk4K1BIQmhkR2dnWkQwaVRUZ3VNVE15SURndU1EYzRZeTB1TkRZMkxqWTBMVEV1TWprM0lERXVNekl6TFRJdU5qazFJREV1T1RreWJESXVNVEkyTFRVdU56YzNZeTR3T0RrdU1Ea3VNVGt6TGpJd05DNHpMak16T0M0ek1ETXVNemMxTGpZeU5TNDRPVEV1TnpRMElERXVORGcwTGpFeE55NDFPRE11TURRZ01TNHlOVE10TGpRM05TQXhMamsyTTFvaUlHWnBiR3c5SW5WeWJDZ2pZU2tpSUhOMGNtOXJaVDBpSTJabVppSWdjM1J5YjJ0bExYZHBaSFJvUFNJdU5TSXZQanhrWldaelBqeHNhVzVsWVhKSGNtRmthV1Z1ZENCcFpEMGlZU0lnZURFOUlqWXVPVFVpSUhreFBTSXpMamcxTXlJZ2VESTlJall1T1RVaUlIa3lQU0l4TUM0MU5EUWlJR2R5WVdScFpXNTBWVzVwZEhNOUluVnpaWEpUY0dGalpVOXVWWE5sSWo0OGMzUnZjQ0J6ZEc5d0xXTnZiRzl5UFNJak9ESXdNakF5SWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TVRneUlpQnpkRzl3TFdOdmJHOXlQU0lqUmpjeFJUQTFJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOVEUySWlCemRHOXdMV052Ykc5eVBTSWpSakJHTlRBM0lpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU56TTBJaUJ6ZEc5d0xXTnZiRzl5UFNJak9EVkRSRGMxSWk4K1BITjBiM0FnYjJabWMyVjBQU0l4SWlCemRHOXdMV052Ykc5eVBTSWpNREk1UkVaQ0lpOCtQQzlzYVc1bFlYSkhjbUZrYVdWdWRENDhMMlJsWm5NK1BDOW5QanhuSUdsa1BTSjFja0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNM1JqVTFNek1pTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSjFja0pGUVU1RlZFZ2lQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RRZ01TNHlOalV0TXk0MU1EVWdPUzR6Tm1NdU1EQXpJREF0TXk0NE9EUXROaTQyTWpVZ015NDFNRFV0T1M0ek5sb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNDVOVElnTmk0NU9EWmhMakEyTXk0d05qTWdNQ0F3SURFdExqQXlNaTR3TUROakxTNDNNUzR4TXkweExqUXlOQzR5TlRVdE1pNHhNelF1TXpneExTNHlPREV1TURVeUxTNDFOalV1TVRBekxTNDRORFl1TVRVeVlTNHdNell1TURNMklEQWdNQ0F4TFM0d01qWWdNR3d5TGpFMExUVXVOakkxTGpBd05DMHVNREF6WXk0eU9UY2dNUzQzTURJdU5Ua2dNeTR6T1RRdU9EZzBJRFV1TURreVdtMHRMakU0Tnk0ME56aGpMVEV1TWpZMkxqZzFPUzB5TGpVek1TQXhMamN5TVMwekxqZ2dNaTQxT0d3dU56Z3hMVEl1TURVMFl5NHdNRGN1TURBMExqQXhNeUF3SUM0d01qTWdNQ0F1TnpVNUxTNHhNeklnTVM0MU1UUXRMakkyT0NBeUxqSTNMUzQwYkM0Mk9UY3RMakV5Tmk0d015MHVNREEyWXkwdU1EQTBMakF3TXlBd0lDNHdNRFlnTUNBdU1EQTJXaUlnWm1sc2JEMGlJekF3TUNJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1JaUI0UFNJdE1qUWlJSGs5SWkweE5DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB6TmlJZ2VUMGlMVEl4SWk4K1BDOW5Qand2WkdWbWN6NDhjbVZqZENCM2FXUjBhRDBpTWpVMUlpQm9aV2xuYUhROUlqTTFNQ0lnY25nOUlqRXdJaUJtYVd4c1BTSWpNalV6TXpJMklpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjMmxzYnlJZ2VEMGlPVGtpSUhrOUlqVTFJaTgrUEdjZ2FXUTlJbUZzYkZCc2IzUWlJR05zYVhBdGNHRjBhRDBpZFhKc0tDTmliM0prWlhKTllYTnJLU0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXROamtpSUhrOUlpMHhOalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVEUyTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpBaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJeE16Z2lJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXRNVEkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRnMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNVE00SWlCNVBTSXRORFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzTnBiRzhpSUhnOUlqUTNJaUI1UFNJMU5TSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMamNwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l6TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpFek9DSWdlVDBpTXpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JoY25ScFlXeE1aV0ZtVUd4dmRDSWdlRDBpTmpraUlIazlJamMySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTFRFek9DSWdlVDBpTVRFMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlNQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNVE00SWlCNVBTSXhNVFlpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlNVFUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l4TlRZaUlDOCtQQzluUGp4eVpXTjBJSGc5SWpBaUlIazlJakFpSUhkcFpIUm9QU0l5TlRVaUlHaGxhV2RvZEQwaU1qQWlJSEo0UFNJMUlpQm1hV3hzUFNJak1qUXlOREkwSWk4K1BIUmxlSFFnZUQwaU1UQWlJSGs5SWpFMExqVWlJR1p2Ym5RdGMybDZaVDBpTVRJaUlHWnBiR3c5SWxkb2FYUmxJaUIwWlhoMExXRnVZMmh2Y2owaWMzUmhjblFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBuVnlRa1ZCVGlCRVpYQnZjMmwwUEM5MFpYaDBQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM1Z5UWtWQlRpSWdlRDBpTWpRd0lpQjVQU0kwSWlBdlBqeHlaV04wSUhnOUlqQWlJSGs5SWpNek1DSWdkMmxrZEdnOUlqSTFOU0lnYUdWcFoyaDBQU0l5TUNJZ2NuZzlJalVpSUdacGJHdzlJaU15TkRJME1qUWlMejQ4ZEdWNGRDQjRQU0l4TWpjaUlIazlJak0wTXlJZ1ptOXVkQzF6YVhwbFBTSXhNQ0lnWm1sc2JEMGlWMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0p0YVdSa2JHVWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGp4MGMzQmhiajQ4WVc1cGJXRjBaU0JoZEhSeWFXSjFkR1ZPWVcxbFBTSjRJaUJtY205dFBTSXpOelVpSUhSdlBTSTFNQ0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNE1XSmxZVEF3TlRCbE5qTmxNRFZtWW1JMVpEaGlZVEptTVRCalpqVTRNREJpTmpJeU5EUTBPVHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqRXlOeUlnZVQwaU16UXpJaUJtYjI1MExYTnBlbVU5SWpFd0lpQm1hV3hzUFNKWGFHbDBaU0lnZEdWNGRDMWhibU5vYjNJOUltMXBaR1JzWlNJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStQSFJ6Y0dGdVBqeGhibWx0WVhSbElHRjBkSEpwWW5WMFpVNWhiV1U5SW5naUlHWnliMjA5SWpVd0lpQjBiejBpTFRJM05TSWdaSFZ5UFNJeE1ITWlJSEpsY0dWaGRFTnZkVzUwUFNKcGJtUmxabWx1YVhSbElpQXZQakI0TVdKbFlUQXdOVEJsTmpObE1EVm1ZbUkxWkRoaVlUSm1NVEJqWmpVNE1EQmlOakl5TkRRME9Ud3ZkSE53WVc0K1BDOTBaWGgwUGp4MFpYaDBJSGc5SWpJek5TSWdlVDBpTVRRdU5TSWdabTl1ZEMxemFYcGxQU0l4TWlJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKbGJtUWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGxOMFpXMDZJREV3TWpROEwzUmxlSFErUEM5emRtYysifQ== \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJ1ckJFQU4ifSwgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiBBZGRyZXNzIiwgInZhbHVlIjogIjB4MWJlYTAwNTBlNjNlMDVmYmI1ZDhiYTJmMTBjZjU4MDBiNjIyNDQ0OSJ9LCB7ICJ0cmFpdF90eXBlIjogIklkIiwgInZhbHVlIjogIjB4MWJlYTAwNTBlNjNlMDVmYmI1ZDhiYTJmMTBjZjU4MDBiNjIyNDQ0OTAwMDAwMDAwMDAwMDAwMDAwMDAwMDQwMCJ9LCB7ICJ0cmFpdF90eXBlIjogInN0ZW0iLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDEwMjR9LCB7ICJ0cmFpdF90eXBlIjogImluaXRhbCBzdGFsayBwZXIgQkRWIiwgImRpc3BsYXlfdHlwZSI6ICJudW1iZXIiLCAidmFsdWUiOiAxMDAwMH0sIHsgInRyYWl0X3R5cGUiOiAiZ3Jvd24gc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogOTc4fSwgeyAidHJhaXRfdHlwZSI6ICJzdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb24iLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDIwMDAwMDAsICJpbWFnZSI6ICJkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUJqYkdGemN6MGljM1puUW05a2VTSWdkMmxrZEdnOUlqSTFOU0lnYUdWcFoyaDBQU0l6TlRBaUlIWnBaWGRDYjNnOUlqQWdNQ0F5TlRVZ016VXdJaUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSGh0Ykc1ek9uaHNhVzVyUFNKb2RIUndPaTh2ZDNkM0xuY3pMbTl5Wnk4eE9UazVMM2hzYVc1cklqNDhaR1ZtY3o0OFp5QnBaRDBpY0d4dmRDSStQSEJoZEdnZ1pEMGlUVGM1TGpVM01qZ2dNVEk1TGpJMk5Vd3hNamN1TkRZNUlERTFOaTQ0TXpOTU1UYzFMalEwTXlBeE1qa3VNalExVERFeU55NDBOamtnTVRBeExqWTVOMHczT1M0MU56STRJREV5T1M0eU5qVmFJaUJtYVd4c1BTSWpPVFEwUVRJM0lpOCtQSEJoZEdnZ1pEMGlUVGM1TGpVek16SWdNVE16TGpReU5rdzNPUzQxTnpJM0lERXlPUzR5TmpWTU1USTNMalEyT1NBeE5UWXVPRE16VERFeU55NDFNRGNnTVRZd0xqa3dPRXczT1M0MU16TXlJREV6TXk0ME1qWmFJaUJtYVd4c1BTSWpOelV6T1RGR0lpOCtQSEJoZEdnZ1pEMGlUVEUzTlM0ME5qY2dNVE16TGpSTU1UYzFMalEwTXlBeE1qa3VNalExVERFeU55NDBOamtnTVRVMkxqZ3pNMHd4TWpjdU5UQTNJREUyTUM0NU1EaE1NVGMxTGpRMk55QXhNek11TkZvaUlHWnBiR3c5SWlNMk56TXpNVVVpTHo0OEwyYytQR2NnYVdROUltWjFiR3hNWldGbVVHeHZkQ0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0d4dmRDSWdlRDBpTFRNMUlpQjVQU0l3SWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5zWldGbVVtOTNJaUI0UFNJdE16VWlJSGs5SWpBaUlHWnBiR3c5SWlOQk9FTTRNMEVpSUhSeVlXNXpabTl5YlQwaWMyTmhiR1VvTVM0MEtTSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdaU2IzY2lJSGc5SWkwME55SWdlVDBpTnlJZ1ptbHNiRDBpSXpnNVFUWXlSaUlnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmxKdmR5SWdlRDBpTFRZd0lpQjVQU0l4TkNJZ1ptbHNiRDBpSTBFNFF6Z3pRU0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmxKdmR5SWdlRDBpTFRjeklpQjVQU0l5TVNJZ1ptbHNiRDBpSXpnNVFUWXlSaUlnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0psYlhCMGVWQnNiM1FpUGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNCc2IzUWlJSGc5SWkwek5TSWdlVDBpTUNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKd1lYSjBhV0ZzVEdWaFpsSnZkeUkrUEM5blBqeG5JR2xrUFNKd1lYSjBhV0ZzVEdWaFpsQnNiM1FpUGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNCc2IzUWlJSGc5SWkwek5TSWdlVDBpTUNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUTTFJaUI1UFNJd0lpQm1hV3hzUFNJalFUaERPRE5CSWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4TDJjK1BHY2dhV1E5SW14bFlXWWlQanh3WVhSb0lHUTlJazB4TnpFdU9EZzBJREV4T0M0NU9ETmhOQzQ1TXpJZ05DNDVNeklnTUNBd0lERXRNUzR3TVRnZ01pNDJNRFlnTkM0M01UVWdOQzQzTVRVZ01DQXdJREV0TVM0NE56Z2dNUzQwTXpsakxTNDBOalV1TVRrMUxURXVOek0xTGpjeU55MHlMak0yTkM0eE56WXRMakkwTmlBekxqSTVPQzB4TGpVNU15QTJMalV4TWkweUxqSTFNeUEzTGprMU5HRTBMalV6TWlBMExqVXpNaUF3SURBZ01TMHVNekV6TFM0NU16TmpMUzR5TVRFdExqazNOUzB1TURNNExURXVOell6TGpBM09DMHlMakk1TlM0eU1ESXRMamt5TVM0ek5UTXRNUzQyTVRJdU5EWTNMVEl1TVRRdE1TNHhOemN1TmprMExUSXVOalF5TGpVMk9TMHpMalUxT0MwdU1qY3lMUzQzT1RZdExqY3pNaTB4TGpBNE15MHhMamt5TVMwdU56UXpMVE11TURNMExqUTVPQzR3TVRFZ01TNDVNemt1TVRBNUlETXVNalEzSURFdU1UWTNZVFV1TVRNZ05TNHhNeUF3SURBZ01TQXhMakl4SURFdU5ERXpZeTR4TlRrdExqYzBMakU1T1MwdU9UVTRMakl6T0MweExqRTNPUzR5TURrdE1TNHlNVE11TXpJeUxURXVPRGN5TGpJM05DMHlMamN5TkdFM0xqY3pJRGN1TnpNZ01DQXdJREF0TGprd09DMHpMakUzTjJNdExqYzNNaTQwTVRVdE1TNDNPRGt1TVRrMkxUSXVNemM0TFM0ek1EUXRMak16T1MwdU1qZzNMUzQxTlRZdExqWTRNaTB1TnpZMExURXVOamt5WVRFeUxqY3pPU0F4TWk0M016a2dNQ0F3SURFdExqRTNOaTB6TGprd09XTXVOemc1TGpZd015QXhMalEzSURFdU1ERTVJREV1T1RNM0lERXVNamd6TGprME5DNDFNellnTVM0ek5EUXVOak01SURFdU56WXhJREV1TVRZM0xqRTFNaTR4T1RNdU5qUTVMamcwTWk0MU9EWWdNUzQzTlRFdExqQXhNUzR4TnpJdExqQTFNeTQzT1RVdExqUTJOQ0F4TGpJNU0yRTJMamd6SURZdU9ETWdNQ0F3SURFZ01TNHpPRFFnTWk0eU1qZGpMakUwTGpNMk9DNHlOREl1TnpRMExqTXhNU0F4TGpFMUxqRXdOeTB1TWpBM0xqSTJNUzB1TkRNNUxqVXhNUzB1TnpJeUxqUTFNeTB1TlRFekxqZzNMUzQ1T1RJZ01TNDJNRFF0TVM0eU9EUXVOamd6TFM0eU56SWdNUzR5T0MwdU1qUTVJREV1TnpJekxTNHlNelJoTlM0ek1ESWdOUzR6TURJZ01DQXdJREVnTVM0ME9EWXVNamN6V2lJdlBqd3ZaejQ4WnlCcFpEMGljMmxzYnlJK1BIQmhkR2dnWkQwaVRUVTNMakV3T0NBM01TNHlPV011TVRnNExURXhMalkxTXkweE1pNHdNUzB5TVM0ek1ETXRNamN1TWpRekxUSXhMalUxTWkweE5TNHlNelF0TGpJMUxUSTNMamN6TmlBNExqazVOUzB5Tnk0NU1qTWdNakF1TmpRNUxTNHhPRGNnTVRFdU5qVTBJREV5TGpBeElESXhMak13TkNBeU55NHlORFFnTWpFdU5UVXpJREUxTGpJek15NHlOU0F5Tnk0M016VXRPQzQ1T1RVZ01qY3VPVEl5TFRJd0xqWTFXaUlnWm1sc2JEMGlJelkyTmlJdlBqeHdZWFJvSUdROUlrMHVORFkwSURFNUxqVTBOR011TmprNUlERTJMalU0TlNBeExqUWdNek11TVRZNUlESXVNRGs0SURRNUxqYzFNaTR3TWpFZ01pNHpPREV1TkRnZ05DNHlOemd1T0RneklEVXVOVE01TGpJM055NDROaTQzTkRFZ01pNHlOelVnTVM0M056Z2dNeTQ0TmpjdU5EazBMamMxT1NBeExqSXhNaUF4TGpjZ015NHdNRElnTXk0ek16SWdNUzQzTXprZ01TNDFPRFlnTXk0ek5TQXpMakExTmlBMUxqY3pNaUEwTGpNNU9DQXpMakk1TXlBeExqZzFOU0EyTGpFMU1TQXlMak01TmlBNExqYzVNU0F5TGpnNU5pQXhMamcxTlM0ek5TQTFMakUwT1M0NU5EZ2dPUzQwT0RndU5UVTJZVE15TGpjd055QXpNaTQzTURjZ01DQXdJREFnT1M0ek1UVXRNaTR5T0Rkak1TNDROakl0TGpjMU9TQTBMalkwTWkweExqa3hOeUEzTGpZek15MDBMalFnTVM0ek5EZ3RNUzR4TWlBekxqUTBPQzB5TGpnNU55QTFMakU1TnkwMUxqazFZVEl3TGpFeE5DQXlNQzR4TVRRZ01DQXdJREFnTWk0eU5TMDFMams1T0dNdU1qRXRNVGN1TlRVeUxqUXlMVE0xTGpFd05DNDJNekl0TlRJdU5qVTNiQzAxTmk0NExqazFNbWd1TURBeFdpSWdabWxzYkQwaUkwSXpRak5DTXlJdlBqeHdZWFJvSUdROUlrMDFOeTQwT0NBeE9TNDBPREpETlRjdU5qUTFJRGt1TWpRZ05EUXVPVGM0TGpjeU55QXlPUzR4T0RjdU5EWTRJREV6TGpNNU55NHlNUzQwTmpNZ09DNHpNRE11TWprNElERTRMalUwTmk0eE16UWdNamd1TnpnNElERXlMamdnTXpjdU15QXlPQzQxT1RFZ016Y3VOVFpqTVRVdU56a3VNalU0SURJNExqY3lOQzAzTGpnek5TQXlPQzQ0T0RrdE1UZ3VNRGM0V2lJZ1ptbHNiRDBpSTBORFF5SXZQanh3WVhSb0lHUTlJazB6TUM0ek1UUWdOeTR4TXpkakxqQXdPUzB1TlRZeExTNDJPQzB4TGpBeU9DMHhMalV6T0MweExqQTBNaTB1T0RVNUxTNHdNVFF0TVM0MU5qSXVORE10TVM0MU56RXVPVGt4TFM0d01TNDFOakl1TmpnZ01TNHdNamdnTVM0MU16Z2dNUzR3TkRJdU9EVTVMakF4TlNBeExqVTJNaTB1TkRNZ01TNDFOeTB1T1RsYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFRZdU5ERTBJREk0TGpnNVlURTFMamMzTnlBeE5TNDNOemNnTUNBd0lERXRNaTR3T1RNdE1pNHhORFpqTFM0NE5UWXRNUzR3TmpNdE1pNDBOVE10TXk0d09UTXRNaTQ1TnpVdE5pNHhNVEpoTVRFdU56WTFJREV4TGpjMk5TQXdJREFnTVMwdU1Ea3pMVE11TXpBM2JESTFMalF6TFRrdU9UYzJZeTR3TkRNdU1UUXlMakU0T0M0MU5UVXVOakEwTGpnMk9DNDBOaTR6TkRZdU9UUTNMak0wSURFdU1EZzJMak16TkV3MkxqUXhNeUF5T0M0NE9EaDJMakF3TWxvaUlHWnBiR3c5SWlORk5rVTJSVFlpTHo0OGNHRjBhQ0J2Y0dGamFYUjVQU0l1TXpNaUlHUTlJazB4TGpRM055QXhOaTR3TWpsakxqSTFMUzQ1TXpFdU56QTJMVEl1TWpVNElERXVOVGN0TXk0Mk9UVXVOalUxTFRFdU1Ea3lJREV1TWpreUxURXVPREkxSURFdU56WXRNaTR6TlRndU5UZzBMUzQyTmpVZ01TNDNOell0TVM0NU16UWdNeTQyTnprdE15NHlPU0F5TGprMU15MHlMakV3TlNBMUxqWTVOaTB6TGpBMUlEY3VOekl6TFRNdU56TmhNemN1TXpVZ016Y3VNelVnTUNBd0lERWdOaTQwT0RVdE1TNDFORGRzTlM0eU5ESWdOQzR6TVRaaE1TNDBPQ0F4TGpRNElEQWdNQ0F3TFRFdU1qRTBMamsyTjB3eExqUTRJREUyTGpBemFDMHVNREF5V2lJZ1ptbHNiRDBpSXprNU9TSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNDBOQ0lnWkQwaVRURXVPREVnTWpZdU5UTXlZeTR5TURZdU5EazBMalE0TkNBeExqQTFMamcySURFdU5qTmhNVEF1TWpZMklERXdMakkyTmlBd0lEQWdNQ0F5TGpJM09DQXlMalE0Tmt3MkxqVTFNaUEzT0M0eU1tRXhOeTR5TnpJZ01UY3VNamN5SURBZ01DQXhMVE10Tnk0ME1UTk1NUzQ0TVNBeU5pNDFNekphSWlCbWFXeHNQU0lqUlRaRk5rVTJJaTgrUEhCaGRHZ2daRDBpYlRNekxqQTVNaUEwT1M0ME5ERXROaTR6T0RFZ01UVXVNakV4Y3kwMkxqQTNPQzB4TVM0eE5Ua2dOaTR6T0RFdE1UVXVNakZhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEhCaGRHZ2daRDBpYlRJMkxqY3lOU0EyTkM0NE5UZ3RMakE1TVMwdU1UYzFZeTB1TURJMkxTNHdORGt0TWk0Mk16UXROQzQ1TWpNdExqZzJOeTA1TGpNM0lERXVNRFUzTFRJdU56RTNJRE11TlRFNExUUXVOekkxSURjdU15MDFMamswTm13dU1UZzNMUzR3TmpFdE5pNDFNeUF4TlM0MU5USmFiVFl1TWpFeUxURTFMakkyT0dNdE15NDJNakVnTVM0eU1UY3ROUzQ1T1RFZ015NHhOamd0Tnk0d01qSWdOUzQzT1RndE1TNDFNemdnTXk0NU1EZ3VNelUxSURndU1UWTJMamM0T0NBNUxqQTFOR3cyTGpJek5DMHhOQzQ0TlRKYVRUSTRMakE1TXlBMk15NDNNemRzTkM0ME9EUXRNVEF1T0Rkek55NHpOalVnTmk0ek16Y3ROQzQwT0RRZ01UQXVPRGRhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEM5blBqeG5JR2xrUFNKQ1JVRk9JajQ4Y21WamRDQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnM0lERXVNalkxTFRNdU5UQTBJRGt1TXpaVExqSTVPQ0F6TGprNU9TQTNMalk0TnlBeExqSTJObHB0TFRJdU5qa3hJRGd1TnpnZ01pNDBOakl0Tmk0Mk9URnpOQzQxTXpnZ015NDJOeTB5TGpRMk1pQTJMalk1TVZvaUlHWnBiR3c5SWlObVptWWlMejQ4TDJjK1BHY2dhV1E5SWtKRlFVNHpRMUpXSWo0OGNtVmpkQ0I1UFNJdU5TSWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE55QXhMamMyTkMwekxqVXdOQ0E1TGpNMlV5NHlPVGdnTkM0ME9Ua2dOeTQyT0RjZ01TNDNOalZhSWlCbWFXeHNQU0lqWm1abUlpOCtQSEJoZEdnZ1pEMGlUVGd1TVRNeUlEZ3VNRGM0WXkwdU5EWTJMalkwTFRFdU1qazNJREV1TXpJekxUSXVOamsxSURFdU9Ua3liREl1TVRJMkxUVXVOemMzWXk0d09Ea3VNRGt1TVRrekxqSXdOQzR6TGpNek9DNHpNRE11TXpjMUxqWXlOUzQ0T1RFdU56UTBJREV1TkRnMExqRXhOeTQxT0RNdU1EUWdNUzR5TlRNdExqUTNOU0F4TGprMk0xb2lJR1pwYkd3OUluVnliQ2dqWVNraUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMWGRwWkhSb1BTSXVOU0l2UGp4a1pXWnpQanhzYVc1bFlYSkhjbUZrYVdWdWRDQnBaRDBpWVNJZ2VERTlJall1T1RVaUlIa3hQU0l6TGpnMU15SWdlREk5SWpZdU9UVWlJSGt5UFNJeE1DNDFORFFpSUdkeVlXUnBaVzUwVlc1cGRITTlJblZ6WlhKVGNHRmpaVTl1VlhObElqNDhjM1J2Y0NCemRHOXdMV052Ykc5eVBTSWpPREl3TWpBeUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU1UZ3lJaUJ6ZEc5d0xXTnZiRzl5UFNJalJqY3hSVEExSWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TlRFMklpQnpkRzl3TFdOdmJHOXlQU0lqUmpCR05UQTNJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOek0wSWlCemRHOXdMV052Ykc5eVBTSWpPRFZEUkRjMUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeElpQnpkRzl3TFdOdmJHOXlQU0lqTURJNVJFWkNJaTgrUEM5c2FXNWxZWEpIY21Ga2FXVnVkRDQ4TDJSbFpuTStQQzluUGp4bklHbGtQU0oxY2tKRlFVNGlQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RjZ01TNHlOalV0TXk0MU1EUWdPUzR6TmxNdU1qazRJRE11T1RrNUlEY3VOamczSURFdU1qWTJXbTB0TWk0Mk9URWdPQzQzT0NBeUxqUTJNaTAyTGpZNU1YTTBMalV6T0NBekxqWTNMVEl1TkRZeUlEWXVOamt4V2lJZ1ptbHNiRDBpSTJabVppSXZQand2Wno0OFp5QnBaRDBpUWtWQlRrVlVTQ0krUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE5DQXhMakkyTlMwekxqVXdOU0E1TGpNMll5NHdNRE1nTUMwekxqZzROQzAyTGpZeU5TQXpMalV3TlMwNUxqTTJXaUlnWm1sc2JEMGlJMlptWmlJdlBqeHdZWFJvSUdROUlrMDRMamsxTWlBMkxqazRObUV1TURZekxqQTJNeUF3SURBZ01TMHVNREl5TGpBd00yTXRMamN4TGpFekxURXVOREkwTGpJMU5TMHlMakV6TkM0ek9ERXRMakk0TVM0d05USXRMalUyTlM0eE1ETXRMamcwTmk0eE5USmhMakF6Tmk0d016WWdNQ0F3SURFdExqQXlOaUF3YkRJdU1UUXROUzQyTWpVdU1EQTBMUzR3TUROakxqSTVOeUF4TGpjd01pNDFPU0F6TGpNNU5DNDRPRFFnTlM0d09USmFiUzB1TVRnM0xqUTNPR010TVM0eU5qWXVPRFU1TFRJdU5UTXhJREV1TnpJeExUTXVPQ0F5TGpVNGJDNDNPREV0TWk0d05UUmpMakF3Tnk0d01EUXVNREV6SURBZ0xqQXlNeUF3SUM0M05Ua3RMakV6TWlBeExqVXhOQzB1TWpZNElESXVNamN0TGpSc0xqWTVOeTB1TVRJMkxqQXpMUzR3TURaakxTNHdNRFF1TURBeklEQWdMakF3TmlBd0lDNHdNRFphSWlCbWFXeHNQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0oxY2tKRlFVNUZWRWdpUGp4eVpXTjBJSGRwWkhSb1BTSXhNaUlnYUdWcFoyaDBQU0l4TWlJZ2NuZzlJallpSUdacGJHdzlJaU0zUmpVMU16TWlMejQ4Y0dGMGFDQmtQU0p0Tnk0Mk9EUWdNUzR5TmpVdE15NDFNRFVnT1M0ek5tTXVNREF6SURBdE15NDRPRFF0Tmk0Mk1qVWdNeTQxTURVdE9TNHpObG9pSUdacGJHdzlJaU5tWm1ZaUx6NDhjR0YwYUNCa1BTSk5PQzQ1TlRJZ05pNDVPRFpoTGpBMk15NHdOak1nTUNBd0lERXRMakF5TWk0d01ETmpMUzQzTVM0eE15MHhMalF5TkM0eU5UVXRNaTR4TXpRdU16Z3hMUzR5T0RFdU1EVXlMUzQxTmpVdU1UQXpMUzQ0TkRZdU1UVXlZUzR3TXpZdU1ETTJJREFnTUNBeExTNHdNallnTUd3eUxqRTBMVFV1TmpJMUxqQXdOQzB1TURBell5NHlPVGNnTVM0M01ESXVOVGtnTXk0ek9UUXVPRGcwSURVdU1Ea3lXbTB0TGpFNE55NDBOemhqTFRFdU1qWTJMamcxT1MweUxqVXpNU0F4TGpjeU1TMHpMamdnTWk0MU9Hd3VOemd4TFRJdU1EVTBZeTR3TURjdU1EQTBMakF4TXlBd0lDNHdNak1nTUNBdU56VTVMUzR4TXpJZ01TNDFNVFF0TGpJMk9DQXlMakkzTFM0MGJDNDJPVGN0TGpFeU5pNHdNeTB1TURBMll5MHVNREEwTGpBd015QXdJQzR3TURZZ01DQXVNREEyV2lJZ1ptbHNiRDBpSXpBd01DSXZQand2Wno0OFp5QnBaRDBpYkdWaFpsSnZkeUkrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTUNJZ2VUMGlNQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweE1pSWdlVDBpTFRjaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXRNalFpSUhrOUlpMHhOQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkwek5pSWdlVDBpTFRJeElpOCtQQzluUGp3dlpHVm1jejQ4Y21WamRDQjNhV1IwYUQwaU1qVTFJaUJvWldsbmFIUTlJak0xTUNJZ2NuZzlJakV3SWlCbWFXeHNQU0lqTWpVek16STJJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYzJsc2J5SWdlRDBpT1RraUlIazlJalUxSWk4K1BHY2dhV1E5SW1Gc2JGQnNiM1FpSUdOc2FYQXRjR0YwYUQwaWRYSnNLQ05pYjNKa1pYSk5ZWE5yS1NJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTB4TmpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRFMk5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqQWlJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l0TVRJMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJdE9EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSTJPU0lnZVQwaUxUZzBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlMVEV6T0NJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTUNJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM05wYkc4aUlIZzlJalEzSWlCNVBTSTFOU0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpjcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqRXpPQ0lnZVQwaU16WWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXROamtpSUhrOUlqYzJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNCaGNuUnBZV3hNWldGbVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTUNJZ2VUMGlNVEUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTVRVMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJeE5UWWlJQzgrUEM5blBqeHlaV04wSUhnOUlqQWlJSGs5SWpBaUlIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNakFpSUhKNFBTSTFJaUJtYVd4c1BTSWpNalF5TkRJMElpOCtQSFJsZUhRZ2VEMGlNVEFpSUhrOUlqRTBMalVpSUdadmJuUXRjMmw2WlQwaU1USWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGljM1JoY25RaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQblZ5UWtWQlRpQkVaWEJ2YzJsMFBDOTBaWGgwUGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTNWeVFrVkJUaUlnZUQwaU1qUXdJaUI1UFNJMElpQXZQanh5WldOMElIZzlJakFpSUhrOUlqTXpNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1qY2lJSGs5SWpNME15SWdabTl1ZEMxemFYcGxQU0l4TUNJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKdGFXUmtiR1VpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBqeDBjM0JoYmo0OFlXNXBiV0YwWlNCaGRIUnlhV0oxZEdWT1lXMWxQU0o0SWlCbWNtOXRQU0l6TnpVaUlIUnZQU0kxTUNJZ1pIVnlQU0l4TUhNaUlISmxjR1ZoZEVOdmRXNTBQU0pwYm1SbFptbHVhWFJsSWlBdlBqQjRNV0psWVRBd05UQmxOak5sTURWbVltSTFaRGhpWVRKbU1UQmpaalU0TURCaU5qSXlORFEwT1R3dmRITndZVzQrUEM5MFpYaDBQangwWlhoMElIZzlJakV5TnlJZ2VUMGlNelF6SWlCbWIyNTBMWE5wZW1VOUlqRXdJaUJtYVd4c1BTSlhhR2wwWlNJZ2RHVjRkQzFoYm1Ob2IzSTlJbTFwWkdSc1pTSWdabTl1ZEMxbVlXMXBiSGs5SW1aMWRIVnlZU0krUEhSemNHRnVQanhoYm1sdFlYUmxJR0YwZEhKcFluVjBaVTVoYldVOUluZ2lJR1p5YjIwOUlqVXdJaUIwYnowaUxUSTNOU0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNE1XSmxZVEF3TlRCbE5qTmxNRFZtWW1JMVpEaGlZVEptTVRCalpqVTRNREJpTmpJeU5EUTBPVHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqSXpOU0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSmxibVFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBsTjBaVzA2SURFd01qUThMM1JsZUhRK1BDOXpkbWMrIn0= \ No newline at end of file diff --git a/protocol/test/data/base64EncodedImageUrBeanEth.txt b/protocol/test/data/base64EncodedImageUrBeanEth.txt index d6be106d40..00e851abe0 100644 --- a/protocol/test/data/base64EncodedImageUrBeanEth.txt +++ b/protocol/test/data/base64EncodedImageUrBeanEth.txt @@ -1 +1 @@ -data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLlxuXG5Ub2tlbiBTeW1ib2w6IHVyQkVBTkVUSFxuVG9rZW4gQWRkcmVzczogMHgxYmVhM2NjZDIyZjRlYmQzZDM3ZDczMWJhMzFlZWNhOTU3MTM3MTZkXG5JZDogMHgxYmVhM2NjZDIyZjRlYmQzZDM3ZDczMWJhMzFlZWNhOTU3MTM3MTZkZmZmZmZmZmZmZmZmZmZmZmZmZmZmOTdjXG5zdGVtOiAtMTY2OFxuaW5pdGFsIHN0YWxrIHBlciBCRFY6IDEwMDAwXG5ncm93biBzdGFsayBwZXIgQkRWOiAzNjcwXG5zdGFsayBncm93biBwZXIgQkRWIHBlciBzZWFzb246IDIwMDAwMDBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCamJHRnpjejBpYzNablFtOWtlU0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJek5UQWlJSFpwWlhkQ2IzZzlJakFnTUNBeU5UVWdNelV3SWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhodGJHNXpPbmhzYVc1clBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJajQ4WkdWbWN6NDhaeUJwWkQwaWNHeHZkQ0krUEhCaGRHZ2daRDBpVFRjNUxqVTNNamdnTVRJNUxqSTJOVXd4TWpjdU5EWTVJREUxTmk0NE16Tk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UQXhMalk1TjB3M09TNDFOekk0SURFeU9TNHlOalZhSWlCbWFXeHNQU0lqT1RRMFFUSTNJaTgrUEhCaGRHZ2daRDBpVFRjNUxqVXpNeklnTVRNekxqUXlOa3czT1M0MU56STNJREV5T1M0eU5qVk1NVEkzTGpRMk9TQXhOVFl1T0RNelRERXlOeTQxTURjZ01UWXdMamt3T0V3M09TNDFNek15SURFek15NDBNalphSWlCbWFXeHNQU0lqTnpVek9URkdJaTgrUEhCaGRHZ2daRDBpVFRFM05TNDBOamNnTVRNekxqUk1NVGMxTGpRME15QXhNamt1TWpRMVRERXlOeTQwTmprZ01UVTJMamd6TTB3eE1qY3VOVEEzSURFMk1DNDVNRGhNTVRjMUxqUTJOeUF4TXpNdU5Gb2lJR1pwYkd3OUlpTTJOek16TVVVaUx6NDhMMmMrUEdjZ2FXUTlJbVoxYkd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1VbTkzSWlCNFBTSXRNelVpSUhrOUlqQWlJR1pwYkd3OUlpTkJPRU00TTBFaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb01TNDBLU0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWlNiM2NpSUhnOUlpMDBOeUlnZVQwaU55SWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUWXdJaUI1UFNJeE5DSWdabWxzYkQwaUkwRTRRemd6UVNJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFpsSnZkeUlnZUQwaUxUY3pJaUI1UFNJeU1TSWdabWxzYkQwaUl6ZzVRVFl5UmlJZ2RISmhibk5tYjNKdFBTSnpZMkZzWlNneExqUXBJaTgrUEM5blBqeG5JR2xrUFNKbGJYQjBlVkJzYjNRaVBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzQnNiM1FpSUhnOUlpMHpOU0lnZVQwaU1DSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSndZWEowYVdGc1RHVmhabEp2ZHlJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhaaUlnZUQwaU1DSWdlVDBpTUNJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1lpSUhnOUlpMHhNaUlnZVQwaUxUY2lMejQ4TDJjK1BHY2dhV1E5SW5CaGNuUnBZV3hNWldGbVVHeHZkQ0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqY0d4dmRDSWdlRDBpTFRNMUlpQjVQU0l3SWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU53WVhKMGFXRnNUR1ZoWmxKdmR5SWdlRDBpTFRNMUlpQjVQU0l3SWlCbWFXeHNQU0lqUVRoRE9ETkJJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhMMmMrUEdjZ2FXUTlJbXhsWVdZaVBqeHdZWFJvSUdROUlrMHhOekV1T0RnMElERXhPQzQ1T0ROaE5DNDVNeklnTkM0NU16SWdNQ0F3SURFdE1TNHdNVGdnTWk0Mk1EWWdOQzQzTVRVZ05DNDNNVFVnTUNBd0lERXRNUzQ0TnpnZ01TNDBNemxqTFM0ME5qVXVNVGsxTFRFdU56TTFMamN5TnkweUxqTTJOQzR4TnpZdExqSTBOaUF6TGpJNU9DMHhMalU1TXlBMkxqVXhNaTB5TGpJMU15QTNMamsxTkdFMExqVXpNaUEwTGpVek1pQXdJREFnTVMwdU16RXpMUzQ1TXpOakxTNHlNVEV0TGprM05TMHVNRE00TFRFdU56WXpMakEzT0MweUxqSTVOUzR5TURJdExqa3lNUzR6TlRNdE1TNDJNVEl1TkRZM0xUSXVNVFF0TVM0eE56Y3VOamswTFRJdU5qUXlMalUyT1MwekxqVTFPQzB1TWpjeUxTNDNPVFl0TGpjek1pMHhMakE0TXkweExqa3lNUzB1TnpRekxUTXVNRE0wTGpRNU9DNHdNVEVnTVM0NU16a3VNVEE1SURNdU1qUTNJREV1TVRZM1lUVXVNVE1nTlM0eE15QXdJREFnTVNBeExqSXhJREV1TkRFell5NHhOVGt0TGpjMExqRTVPUzB1T1RVNExqSXpPQzB4TGpFM09TNHlNRGt0TVM0eU1UTXVNekl5TFRFdU9EY3lMakkzTkMweUxqY3lOR0UzTGpjeklEY3VOek1nTUNBd0lEQXRMamt3T0MwekxqRTNOMk10TGpjM01pNDBNVFV0TVM0M09Ea3VNVGsyTFRJdU16YzRMUzR6TURRdExqTXpPUzB1TWpnM0xTNDFOVFl0TGpZNE1pMHVOelkwTFRFdU5qa3lZVEV5TGpjek9TQXhNaTQzTXprZ01DQXdJREV0TGpFM05pMHpMamt3T1dNdU56ZzVMall3TXlBeExqUTNJREV1TURFNUlERXVPVE0zSURFdU1qZ3pMamswTkM0MU16WWdNUzR6TkRRdU5qTTVJREV1TnpZeElERXVNVFkzTGpFMU1pNHhPVE11TmpRNUxqZzBNaTQxT0RZZ01TNDNOVEV0TGpBeE1TNHhOekl0TGpBMU15NDNPVFV0TGpRMk5DQXhMakk1TTJFMkxqZ3pJRFl1T0RNZ01DQXdJREVnTVM0ek9EUWdNaTR5TWpkakxqRTBMak0yT0M0eU5ESXVOelEwTGpNeE1TQXhMakUxTGpFd055MHVNakEzTGpJMk1TMHVORE01TGpVeE1TMHVOekl5TGpRMU15MHVOVEV6TGpnM0xTNDVPVElnTVM0Mk1EUXRNUzR5T0RRdU5qZ3pMUzR5TnpJZ01TNHlPQzB1TWpRNUlERXVOekl6TFM0eU16UmhOUzR6TURJZ05TNHpNRElnTUNBd0lERWdNUzQwT0RZdU1qY3pXaUl2UGp3dlp6NDhaeUJwWkQwaWMybHNieUkrUEhCaGRHZ2daRDBpVFRVM0xqRXdPQ0EzTVM0eU9XTXVNVGc0TFRFeExqWTFNeTB4TWk0d01TMHlNUzR6TURNdE1qY3VNalF6TFRJeExqVTFNaTB4TlM0eU16UXRMakkxTFRJM0xqY3pOaUE0TGprNU5TMHlOeTQ1TWpNZ01qQXVOalE1TFM0eE9EY2dNVEV1TmpVMElERXlMakF4SURJeExqTXdOQ0F5Tnk0eU5EUWdNakV1TlRVeklERTFMakl6TXk0eU5TQXlOeTQzTXpVdE9DNDVPVFVnTWpjdU9USXlMVEl3TGpZMVdpSWdabWxzYkQwaUl6WTJOaUl2UGp4d1lYUm9JR1E5SWswdU5EWTBJREU1TGpVME5HTXVOams1SURFMkxqVTROU0F4TGpRZ016TXVNVFk1SURJdU1EazRJRFE1TGpjMU1pNHdNakVnTWk0ek9ERXVORGdnTkM0eU56Z3VPRGd6SURVdU5UTTVMakkzTnk0NE5pNDNOREVnTWk0eU56VWdNUzQzTnpnZ015NDROamN1TkRrMExqYzFPU0F4TGpJeE1pQXhMamNnTXk0d01ESWdNeTR6TXpJZ01TNDNNemtnTVM0MU9EWWdNeTR6TlNBekxqQTFOaUExTGpjek1pQTBMak01T0NBekxqSTVNeUF4TGpnMU5TQTJMakUxTVNBeUxqTTVOaUE0TGpjNU1TQXlMamc1TmlBeExqZzFOUzR6TlNBMUxqRTBPUzQ1TkRnZ09TNDBPRGd1TlRVMllUTXlMamN3TnlBek1pNDNNRGNnTUNBd0lEQWdPUzR6TVRVdE1pNHlPRGRqTVM0NE5qSXRMamMxT1NBMExqWTBNaTB4TGpreE55QTNMall6TXkwMExqUWdNUzR6TkRndE1TNHhNaUF6TGpRME9DMHlMamc1TnlBMUxqRTVOeTAxTGprMVlUSXdMakV4TkNBeU1DNHhNVFFnTUNBd0lEQWdNaTR5TlMwMUxqazVPR011TWpFdE1UY3VOVFV5TGpReUxUTTFMakV3TkM0Mk16SXROVEl1TmpVM2JDMDFOaTQ0TGprMU1tZ3VNREF4V2lJZ1ptbHNiRDBpSTBJelFqTkNNeUl2UGp4d1lYUm9JR1E5SWswMU55NDBPQ0F4T1M0ME9ESkROVGN1TmpRMUlEa3VNalFnTkRRdU9UYzRMamN5TnlBeU9TNHhPRGN1TkRZNElERXpMak01Tnk0eU1TNDBOak1nT0M0ek1ETXVNams0SURFNExqVTBOaTR4TXpRZ01qZ3VOemc0SURFeUxqZ2dNemN1TXlBeU9DNDFPVEVnTXpjdU5UWmpNVFV1TnprdU1qVTRJREk0TGpjeU5DMDNMamd6TlNBeU9DNDRPRGt0TVRndU1EYzRXaUlnWm1sc2JEMGlJME5EUXlJdlBqeHdZWFJvSUdROUlrMHpNQzR6TVRRZ055NHhNemRqTGpBd09TMHVOVFl4TFM0Mk9DMHhMakF5T0MweExqVXpPQzB4TGpBME1pMHVPRFU1TFM0d01UUXRNUzQxTmpJdU5ETXRNUzQxTnpFdU9Ua3hMUzR3TVM0MU5qSXVOamdnTVM0d01qZ2dNUzQxTXpnZ01TNHdOREl1T0RVNUxqQXhOU0F4TGpVMk1pMHVORE1nTVM0MU55MHVPVGxhSWlCbWFXeHNQU0lqTmpZMklpOCtQSEJoZEdnZ1pEMGlUVFl1TkRFMElESTRMamc1WVRFMUxqYzNOeUF4TlM0M056Y2dNQ0F3SURFdE1pNHdPVE10TWk0eE5EWmpMUzQ0TlRZdE1TNHdOak10TWk0ME5UTXRNeTR3T1RNdE1pNDVOelV0Tmk0eE1USmhNVEV1TnpZMUlERXhMamMyTlNBd0lEQWdNUzB1TURrekxUTXVNekEzYkRJMUxqUXpMVGt1T1RjMll5NHdORE11TVRReUxqRTRPQzQxTlRVdU5qQTBMamcyT0M0ME5pNHpORFl1T1RRM0xqTTBJREV1TURnMkxqTXpORXcyTGpReE15QXlPQzQ0T0RoMkxqQXdNbG9pSUdacGJHdzlJaU5GTmtVMlJUWWlMejQ4Y0dGMGFDQnZjR0ZqYVhSNVBTSXVNek1pSUdROUlrMHhMalEzTnlBeE5pNHdNamxqTGpJMUxTNDVNekV1TnpBMkxUSXVNalU0SURFdU5UY3RNeTQyT1RVdU5qVTFMVEV1TURreUlERXVNamt5TFRFdU9ESTFJREV1TnpZdE1pNHpOVGd1TlRnMExTNDJOalVnTVM0M056WXRNUzQ1TXpRZ015NDJOemt0TXk0eU9TQXlMamsxTXkweUxqRXdOU0ExTGpZNU5pMHpMakExSURjdU56SXpMVE11TnpOaE16Y3VNelVnTXpjdU16VWdNQ0F3SURFZ05pNDBPRFV0TVM0MU5EZHNOUzR5TkRJZ05DNHpNVFpoTVM0ME9DQXhMalE0SURBZ01DQXdMVEV1TWpFMExqazJOMHd4TGpRNElERTJMakF6YUMwdU1EQXlXaUlnWm1sc2JEMGlJems1T1NJdlBqeHdZWFJvSUc5d1lXTnBkSGs5SWk0ME5DSWdaRDBpVFRFdU9ERWdNall1TlRNeVl5NHlNRFl1TkRrMExqUTROQ0F4TGpBMUxqZzJJREV1TmpOaE1UQXVNalkySURFd0xqSTJOaUF3SURBZ01DQXlMakkzT0NBeUxqUTROa3cyTGpVMU1pQTNPQzR5TW1FeE55NHlOeklnTVRjdU1qY3lJREFnTUNBeExUTXROeTQwTVROTU1TNDRNU0F5Tmk0MU16SmFJaUJtYVd4c1BTSWpSVFpGTmtVMklpOCtQSEJoZEdnZ1pEMGliVE16TGpBNU1pQTBPUzQwTkRFdE5pNHpPREVnTVRVdU1qRXhjeTAyTGpBM09DMHhNUzR4TlRrZ05pNHpPREV0TVRVdU1qRmFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQSEJoZEdnZ1pEMGliVEkyTGpjeU5TQTJOQzQ0TlRndExqQTVNUzB1TVRjMVl5MHVNREkyTFM0d05Ea3RNaTQyTXpRdE5DNDVNak10TGpnMk55MDVMak0zSURFdU1EVTNMVEl1TnpFM0lETXVOVEU0TFRRdU56STFJRGN1TXkwMUxqazBObXd1TVRnM0xTNHdOakV0Tmk0MU15QXhOUzQxTlRKYWJUWXVNakV5TFRFMUxqSTJPR010TXk0Mk1qRWdNUzR5TVRjdE5TNDVPVEVnTXk0eE5qZ3ROeTR3TWpJZ05TNDNPVGd0TVM0MU16Z2dNeTQ1TURndU16VTFJRGd1TVRZMkxqYzRPQ0E1TGpBMU5HdzJMakl6TkMweE5DNDROVEphVFRJNExqQTVNeUEyTXk0M016ZHNOQzQwT0RRdE1UQXVPRGR6Tnk0ek5qVWdOaTR6TXpjdE5DNDBPRFFnTVRBdU9EZGFJaUJtYVd4c1BTSWpPRVU0UlRoRklpOCtQQzluUGp4bklHbGtQU0pDUlVGT0lqNDhjbVZqZENCM2FXUjBhRDBpTVRJaUlHaGxhV2RvZEQwaU1USWlJSEo0UFNJMklpQm1hV3hzUFNJak5EWkNPVFUxSWk4K1BIQmhkR2dnWkQwaWJUY3VOamczSURFdU1qWTFMVE11TlRBMElEa3VNelpUTGpJNU9DQXpMams1T1NBM0xqWTROeUF4TGpJMk5scHRMVEl1TmpreElEZ3VOemdnTWk0ME5qSXROaTQyT1RGek5DNDFNemdnTXk0Mk55MHlMalEyTWlBMkxqWTVNVm9pSUdacGJHdzlJaU5tWm1ZaUx6NDhMMmMrUEdjZ2FXUTlJa0pGUVU0elExSldJajQ4Y21WamRDQjVQU0l1TlNJZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TnlBeExqYzJOQzB6TGpVd05DQTVMak0yVXk0eU9UZ2dOQzQwT1RrZ055NDJPRGNnTVM0M05qVmFJaUJtYVd4c1BTSWpabVptSWk4K1BIQmhkR2dnWkQwaVRUZ3VNVE15SURndU1EYzRZeTB1TkRZMkxqWTBMVEV1TWprM0lERXVNekl6TFRJdU5qazFJREV1T1RreWJESXVNVEkyTFRVdU56YzNZeTR3T0RrdU1Ea3VNVGt6TGpJd05DNHpMak16T0M0ek1ETXVNemMxTGpZeU5TNDRPVEV1TnpRMElERXVORGcwTGpFeE55NDFPRE11TURRZ01TNHlOVE10TGpRM05TQXhMamsyTTFvaUlHWnBiR3c5SW5WeWJDZ2pZU2tpSUhOMGNtOXJaVDBpSTJabVppSWdjM1J5YjJ0bExYZHBaSFJvUFNJdU5TSXZQanhrWldaelBqeHNhVzVsWVhKSGNtRmthV1Z1ZENCcFpEMGlZU0lnZURFOUlqWXVPVFVpSUhreFBTSXpMamcxTXlJZ2VESTlJall1T1RVaUlIa3lQU0l4TUM0MU5EUWlJR2R5WVdScFpXNTBWVzVwZEhNOUluVnpaWEpUY0dGalpVOXVWWE5sSWo0OGMzUnZjQ0J6ZEc5d0xXTnZiRzl5UFNJak9ESXdNakF5SWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TVRneUlpQnpkRzl3TFdOdmJHOXlQU0lqUmpjeFJUQTFJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOVEUySWlCemRHOXdMV052Ykc5eVBTSWpSakJHTlRBM0lpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU56TTBJaUJ6ZEc5d0xXTnZiRzl5UFNJak9EVkRSRGMxSWk4K1BITjBiM0FnYjJabWMyVjBQU0l4SWlCemRHOXdMV052Ykc5eVBTSWpNREk1UkVaQ0lpOCtQQzlzYVc1bFlYSkhjbUZrYVdWdWRENDhMMlJsWm5NK1BDOW5QanhuSUdsa1BTSjFja0pGUVU0aVBqeHlaV04wSUhkcFpIUm9QU0l4TWlJZ2FHVnBaMmgwUFNJeE1pSWdjbmc5SWpZaUlHWnBiR3c5SWlNM1JqVTFNek1pTHo0OGNHRjBhQ0JrUFNKdE55NDJPRGNnTVM0eU5qVXRNeTQxTURRZ09TNHpObE11TWprNElETXVPVGs1SURjdU5qZzNJREV1TWpZMldtMHRNaTQyT1RFZ09DNDNPQ0F5TGpRMk1pMDJMalk1TVhNMExqVXpPQ0F6TGpZM0xUSXVORFl5SURZdU5qa3hXaUlnWm1sc2JEMGlJMlptWmlJdlBqd3ZaejQ4WnlCcFpEMGlRa1ZCVGtWVVNDSStQSEpsWTNRZ2QybGtkR2c5SWpFeUlpQm9aV2xuYUhROUlqRXlJaUJ5ZUQwaU5pSWdabWxzYkQwaUl6UTJRamsxTlNJdlBqeHdZWFJvSUdROUltMDNMalk0TkNBeExqSTJOUzB6TGpVd05TQTVMak0yWXk0d01ETWdNQzB6TGpnNE5DMDJMall5TlNBekxqVXdOUzA1TGpNMldpSWdabWxzYkQwaUkyWm1aaUl2UGp4d1lYUm9JR1E5SWswNExqazFNaUEyTGprNE5tRXVNRFl6TGpBMk15QXdJREFnTVMwdU1ESXlMakF3TTJNdExqY3hMakV6TFRFdU5ESTBMakkxTlMweUxqRXpOQzR6T0RFdExqSTRNUzR3TlRJdExqVTJOUzR4TURNdExqZzBOaTR4TlRKaExqQXpOaTR3TXpZZ01DQXdJREV0TGpBeU5pQXdiREl1TVRRdE5TNDJNalV1TURBMExTNHdNRE5qTGpJNU55QXhMamN3TWk0MU9TQXpMak01TkM0NE9EUWdOUzR3T1RKYWJTMHVNVGczTGpRM09HTXRNUzR5TmpZdU9EVTVMVEl1TlRNeElERXVOekl4TFRNdU9DQXlMalU0YkM0M09ERXRNaTR3TlRSakxqQXdOeTR3TURRdU1ERXpJREFnTGpBeU15QXdJQzQzTlRrdExqRXpNaUF4TGpVeE5DMHVNalk0SURJdU1qY3RMalJzTGpZNU55MHVNVEkyTGpBekxTNHdNRFpqTFM0d01EUXVNREF6SURBZ0xqQXdOaUF3SUM0d01EWmFJaUJtYVd4c1BTSWpNREF3SWk4K1BDOW5QanhuSUdsa1BTSjFja0pGUVU1RlZFZ2lQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RRZ01TNHlOalV0TXk0MU1EVWdPUzR6Tm1NdU1EQXpJREF0TXk0NE9EUXROaTQyTWpVZ015NDFNRFV0T1M0ek5sb2lJR1pwYkd3OUlpTm1abVlpTHo0OGNHRjBhQ0JrUFNKTk9DNDVOVElnTmk0NU9EWmhMakEyTXk0d05qTWdNQ0F3SURFdExqQXlNaTR3TUROakxTNDNNUzR4TXkweExqUXlOQzR5TlRVdE1pNHhNelF1TXpneExTNHlPREV1TURVeUxTNDFOalV1TVRBekxTNDRORFl1TVRVeVlTNHdNell1TURNMklEQWdNQ0F4TFM0d01qWWdNR3d5TGpFMExUVXVOakkxTGpBd05DMHVNREF6WXk0eU9UY2dNUzQzTURJdU5Ua2dNeTR6T1RRdU9EZzBJRFV1TURreVdtMHRMakU0Tnk0ME56aGpMVEV1TWpZMkxqZzFPUzB5TGpVek1TQXhMamN5TVMwekxqZ2dNaTQxT0d3dU56Z3hMVEl1TURVMFl5NHdNRGN1TURBMExqQXhNeUF3SUM0d01qTWdNQ0F1TnpVNUxTNHhNeklnTVM0MU1UUXRMakkyT0NBeUxqSTNMUzQwYkM0Mk9UY3RMakV5Tmk0d015MHVNREEyWXkwdU1EQTBMakF3TXlBd0lDNHdNRFlnTUNBdU1EQTJXaUlnWm1sc2JEMGlJekF3TUNJdlBqd3ZaejQ4WnlCcFpEMGliR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOc1pXRm1JaUI0UFNJdE1qUWlJSGs5SWkweE5DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB6TmlJZ2VUMGlMVEl4SWk4K1BDOW5Qand2WkdWbWN6NDhjbVZqZENCM2FXUjBhRDBpTWpVMUlpQm9aV2xuYUhROUlqTTFNQ0lnY25nOUlqRXdJaUJtYVd4c1BTSWpNalV6TXpJMklpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjMmxzYnlJZ2VEMGlPVGtpSUhrOUlqVTFJaTgrUEdjZ2FXUTlJbUZzYkZCc2IzUWlJR05zYVhBdGNHRjBhRDBpZFhKc0tDTmliM0prWlhKTllYTnJLU0krUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXROamtpSUhrOUlpMHhOalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0kyT1NJZ2VUMGlMVEUyTkNJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTmxiWEIwZVZCc2IzUWlJSGc5SWpBaUlIazlJaTB4TWpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJeE16Z2lJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXRNVE00SWlCNVBTSXRNVEkwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTFRZNUlpQjVQU0l0T0RRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRnMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNQ0lnZVQwaUxUUTBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlNVE00SWlCNVBTSXRORFFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTmpraUlIazlJaTAwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzTnBiRzhpSUhnOUlqUTNJaUI1UFNJMU5TSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMamNwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l6TmlJZ0x6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTndZWEowYVdGc1RHVmhabEJzYjNRaUlIZzlJakV6T0NJZ2VUMGlNellpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJamMySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxURXpPQ0lnZVQwaU1URTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJaMWJHeE1aV0ZtVUd4dmRDSWdlRDBpTUNJZ2VUMGlNVEUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l4TVRZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTVRVMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJeE5UWWlJQzgrUEM5blBqeHlaV04wSUhnOUlqQWlJSGs5SWpBaUlIZHBaSFJvUFNJeU5UVWlJR2hsYVdkb2REMGlNakFpSUhKNFBTSTFJaUJtYVd4c1BTSWpNalF5TkRJMElpOCtQSFJsZUhRZ2VEMGlNVEFpSUhrOUlqRTBMalVpSUdadmJuUXRjMmw2WlQwaU1USWlJR1pwYkd3OUlsZG9hWFJsSWlCMFpYaDBMV0Z1WTJodmNqMGljM1JoY25RaUlHWnZiblF0Wm1GdGFXeDVQU0ptZFhSMWNtRWlQblZ5UWtWQlRrVlVTQ0JFWlhCdmMybDBQQzkwWlhoMFBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkzVnlRa1ZCVGtWVVNDSWdlRDBpTWpRd0lpQjVQU0kwSWlBdlBqeHlaV04wSUhnOUlqQWlJSGs5SWpNek1DSWdkMmxrZEdnOUlqSTFOU0lnYUdWcFoyaDBQU0l5TUNJZ2NuZzlJalVpSUdacGJHdzlJaU15TkRJME1qUWlMejQ4ZEdWNGRDQjRQU0l4TWpjaUlIazlJak0wTXlJZ1ptOXVkQzF6YVhwbFBTSXhNQ0lnWm1sc2JEMGlWMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0p0YVdSa2JHVWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGp4MGMzQmhiajQ4WVc1cGJXRjBaU0JoZEhSeWFXSjFkR1ZPWVcxbFBTSjRJaUJtY205dFBTSXpOelVpSUhSdlBTSTFNQ0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNE1XSmxZVE5qWTJReU1tWTBaV0prTTJRek4yUTNNekZpWVRNeFpXVmpZVGsxTnpFek56RTJaRHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqRXlOeUlnZVQwaU16UXpJaUJtYjI1MExYTnBlbVU5SWpFd0lpQm1hV3hzUFNKWGFHbDBaU0lnZEdWNGRDMWhibU5vYjNJOUltMXBaR1JzWlNJZ1ptOXVkQzFtWVcxcGJIazlJbVoxZEhWeVlTSStQSFJ6Y0dGdVBqeGhibWx0WVhSbElHRjBkSEpwWW5WMFpVNWhiV1U5SW5naUlHWnliMjA5SWpVd0lpQjBiejBpTFRJM05TSWdaSFZ5UFNJeE1ITWlJSEpsY0dWaGRFTnZkVzUwUFNKcGJtUmxabWx1YVhSbElpQXZQakI0TVdKbFlUTmpZMlF5TW1ZMFpXSmtNMlF6TjJRM016RmlZVE14WldWallUazFOekV6TnpFMlpEd3ZkSE53WVc0K1BDOTBaWGgwUGp4MFpYaDBJSGc5SWpJek5TSWdlVDBpTVRRdU5TSWdabTl1ZEMxemFYcGxQU0l4TWlJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKbGJtUWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUGxOMFpXMDZJQzB4TmpZNFBDOTBaWGgwUGp3dmMzWm5QZz09In0= \ No newline at end of file +data:application/json;base64,eyJuYW1lIjogIkJlYW5zdGFsayBTaWxvIERlcG9zaXRzIiwgImRlc2NyaXB0aW9uIjogIkFuIEVSQzExNTUgcmVwcmVzZW50aW5nIGFuIGFzc2V0IGRlcG9zaXRlZCBpbiB0aGUgQmVhbnN0YWxrIFNpbG8uIFNpbG8gRGVwb3NpdHMgZ2FpbiBzdGFsayBhbmQgYmVhbiBzZWlnbm9yYWdlLiBcblxuRElTQ0xBSU1FUjogRHVlIGRpbGlnZW5jZSBpcyBpbXBlcmF0aXZlIHdoZW4gYXNzZXNzaW5nIHRoaXMgTkZULiBPcGVuc2VhIGFuZCBvdGhlciBORlQgbWFya2V0cGxhY2VzIGNhY2hlIHRoZSBzdmcgb3V0cHV0IGFuZCB0aHVzLCBtYXkgcmVxdWlyZSB0aGUgdXNlciB0byByZWZyZXNoIHRoZSBtZXRhZGF0YSB0byBwcm9wZXJseSBzaG93IHRoZSBjb3JyZWN0IHZhbHVlcy4iLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiIsICJ2YWx1ZSI6ICJ1ckJFQU5FVEgifSwgeyAidHJhaXRfdHlwZSI6ICJUb2tlbiBBZGRyZXNzIiwgInZhbHVlIjogIjB4MWJlYTNjY2QyMmY0ZWJkM2QzN2Q3MzFiYTMxZWVjYTk1NzEzNzE2ZCJ9LCB7ICJ0cmFpdF90eXBlIjogIklkIiwgInZhbHVlIjogIjB4MWJlYTNjY2QyMmY0ZWJkM2QzN2Q3MzFiYTMxZWVjYTk1NzEzNzE2ZGZmZmZmZmZmZmZmZmZmZmZmZmZmZjk3YyJ9LCB7ICJ0cmFpdF90eXBlIjogInN0ZW0iLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IC0xNjY4fSwgeyAidHJhaXRfdHlwZSI6ICJpbml0YWwgc3RhbGsgcGVyIEJEViIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMTAwMDB9LCB7ICJ0cmFpdF90eXBlIjogImdyb3duIHN0YWxrIHBlciBCRFYiLCAiZGlzcGxheV90eXBlIjogIm51bWJlciIsICJ2YWx1ZSI6IDM2NzB9LCB7ICJ0cmFpdF90eXBlIjogInN0YWxrIGdyb3duIHBlciBCRFYgcGVyIHNlYXNvbiIsICJkaXNwbGF5X3R5cGUiOiAibnVtYmVyIiwgInZhbHVlIjogMjAwMDAwMCwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmpiR0Z6Y3owaWMzWm5RbTlrZVNJZ2QybGtkR2c5SWpJMU5TSWdhR1ZwWjJoMFBTSXpOVEFpSUhacFpYZENiM2c5SWpBZ01DQXlOVFVnTXpVd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIaHRiRzV6T25oc2FXNXJQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUwzaHNhVzVySWo0OFpHVm1jejQ4WnlCcFpEMGljR3h2ZENJK1BIQmhkR2dnWkQwaVRUYzVMalUzTWpnZ01USTVMakkyTlV3eE1qY3VORFk1SURFMU5pNDRNek5NTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVEF4TGpZNU4wdzNPUzQxTnpJNElERXlPUzR5TmpWYUlpQm1hV3hzUFNJak9UUTBRVEkzSWk4K1BIQmhkR2dnWkQwaVRUYzVMalV6TXpJZ01UTXpMalF5Tmt3M09TNDFOekkzSURFeU9TNHlOalZNTVRJM0xqUTJPU0F4TlRZdU9ETXpUREV5Tnk0MU1EY2dNVFl3TGprd09FdzNPUzQxTXpNeUlERXpNeTQwTWpaYUlpQm1hV3hzUFNJak56VXpPVEZHSWk4K1BIQmhkR2dnWkQwaVRURTNOUzQwTmpjZ01UTXpMalJNTVRjMUxqUTBNeUF4TWprdU1qUTFUREV5Tnk0ME5qa2dNVFUyTGpnek0wd3hNamN1TlRBM0lERTJNQzQ1TURoTU1UYzFMalEyTnlBeE16TXVORm9pSUdacGJHdzlJaU0yTnpNek1VVWlMejQ4TDJjK1BHY2dhV1E5SW1aMWJHeE1aV0ZtVUd4dmRDSStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpjR3h2ZENJZ2VEMGlMVE0xSWlCNVBTSXdJaUIwY21GdWMyWnZjbTA5SW5OallXeGxLREV1TkNraUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtVW05M0lpQjRQU0l0TXpVaUlIazlJakFpSUdacGJHdzlJaU5CT0VNNE0wRWlJSFJ5WVc1elptOXliVDBpYzJOaGJHVW9NUzQwS1NJdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyeGxZV1pTYjNjaUlIZzlJaTAwTnlJZ2VUMGlOeUlnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVFl3SWlCNVBTSXhOQ0lnWm1sc2JEMGlJMEU0UXpnelFTSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamJHVmhabEp2ZHlJZ2VEMGlMVGN6SWlCNVBTSXlNU0lnWm1sc2JEMGlJemc1UVRZeVJpSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3hMalFwSWk4K1BDOW5QanhuSUdsa1BTSmxiWEIwZVZCc2IzUWlQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM0JzYjNRaUlIZzlJaTB6TlNJZ2VUMGlNQ0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpRcElpOCtQQzluUGp4bklHbGtQU0p3WVhKMGFXRnNUR1ZoWmxKdmR5SStQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpiR1ZoWmlJZ2VEMGlNQ0lnZVQwaU1DSXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMnhsWVdZaUlIZzlJaTB4TWlJZ2VUMGlMVGNpTHo0OEwyYytQR2NnYVdROUluQmhjblJwWVd4TVpXRm1VR3h2ZENJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJamNHeHZkQ0lnZUQwaUxUTTFJaUI1UFNJd0lpQjBjbUZ1YzJadmNtMDlJbk5qWVd4bEtERXVOQ2tpTHo0OGRYTmxJSGhzYVc1ck9taHlaV1k5SWlOd1lYSjBhV0ZzVEdWaFpsSnZkeUlnZUQwaUxUTTFJaUI1UFNJd0lpQm1hV3hzUFNJalFUaERPRE5CSWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0RFdU5Da2lMejQ4TDJjK1BHY2dhV1E5SW14bFlXWWlQanh3WVhSb0lHUTlJazB4TnpFdU9EZzBJREV4T0M0NU9ETmhOQzQ1TXpJZ05DNDVNeklnTUNBd0lERXRNUzR3TVRnZ01pNDJNRFlnTkM0M01UVWdOQzQzTVRVZ01DQXdJREV0TVM0NE56Z2dNUzQwTXpsakxTNDBOalV1TVRrMUxURXVOek0xTGpjeU55MHlMak0yTkM0eE56WXRMakkwTmlBekxqSTVPQzB4TGpVNU15QTJMalV4TWkweUxqSTFNeUEzTGprMU5HRTBMalV6TWlBMExqVXpNaUF3SURBZ01TMHVNekV6TFM0NU16TmpMUzR5TVRFdExqazNOUzB1TURNNExURXVOell6TGpBM09DMHlMakk1TlM0eU1ESXRMamt5TVM0ek5UTXRNUzQyTVRJdU5EWTNMVEl1TVRRdE1TNHhOemN1TmprMExUSXVOalF5TGpVMk9TMHpMalUxT0MwdU1qY3lMUzQzT1RZdExqY3pNaTB4TGpBNE15MHhMamt5TVMwdU56UXpMVE11TURNMExqUTVPQzR3TVRFZ01TNDVNemt1TVRBNUlETXVNalEzSURFdU1UWTNZVFV1TVRNZ05TNHhNeUF3SURBZ01TQXhMakl4SURFdU5ERXpZeTR4TlRrdExqYzBMakU1T1MwdU9UVTRMakl6T0MweExqRTNPUzR5TURrdE1TNHlNVE11TXpJeUxURXVPRGN5TGpJM05DMHlMamN5TkdFM0xqY3pJRGN1TnpNZ01DQXdJREF0TGprd09DMHpMakUzTjJNdExqYzNNaTQwTVRVdE1TNDNPRGt1TVRrMkxUSXVNemM0TFM0ek1EUXRMak16T1MwdU1qZzNMUzQxTlRZdExqWTRNaTB1TnpZMExURXVOamt5WVRFeUxqY3pPU0F4TWk0M016a2dNQ0F3SURFdExqRTNOaTB6TGprd09XTXVOemc1TGpZd015QXhMalEzSURFdU1ERTVJREV1T1RNM0lERXVNamd6TGprME5DNDFNellnTVM0ek5EUXVOak01SURFdU56WXhJREV1TVRZM0xqRTFNaTR4T1RNdU5qUTVMamcwTWk0MU9EWWdNUzQzTlRFdExqQXhNUzR4TnpJdExqQTFNeTQzT1RVdExqUTJOQ0F4TGpJNU0yRTJMamd6SURZdU9ETWdNQ0F3SURFZ01TNHpPRFFnTWk0eU1qZGpMakUwTGpNMk9DNHlOREl1TnpRMExqTXhNU0F4TGpFMUxqRXdOeTB1TWpBM0xqSTJNUzB1TkRNNUxqVXhNUzB1TnpJeUxqUTFNeTB1TlRFekxqZzNMUzQ1T1RJZ01TNDJNRFF0TVM0eU9EUXVOamd6TFM0eU56SWdNUzR5T0MwdU1qUTVJREV1TnpJekxTNHlNelJoTlM0ek1ESWdOUzR6TURJZ01DQXdJREVnTVM0ME9EWXVNamN6V2lJdlBqd3ZaejQ4WnlCcFpEMGljMmxzYnlJK1BIQmhkR2dnWkQwaVRUVTNMakV3T0NBM01TNHlPV011TVRnNExURXhMalkxTXkweE1pNHdNUzB5TVM0ek1ETXRNamN1TWpRekxUSXhMalUxTWkweE5TNHlNelF0TGpJMUxUSTNMamN6TmlBNExqazVOUzB5Tnk0NU1qTWdNakF1TmpRNUxTNHhPRGNnTVRFdU5qVTBJREV5TGpBeElESXhMak13TkNBeU55NHlORFFnTWpFdU5UVXpJREUxTGpJek15NHlOU0F5Tnk0M016VXRPQzQ1T1RVZ01qY3VPVEl5TFRJd0xqWTFXaUlnWm1sc2JEMGlJelkyTmlJdlBqeHdZWFJvSUdROUlrMHVORFkwSURFNUxqVTBOR011TmprNUlERTJMalU0TlNBeExqUWdNek11TVRZNUlESXVNRGs0SURRNUxqYzFNaTR3TWpFZ01pNHpPREV1TkRnZ05DNHlOemd1T0RneklEVXVOVE01TGpJM055NDROaTQzTkRFZ01pNHlOelVnTVM0M056Z2dNeTQ0TmpjdU5EazBMamMxT1NBeExqSXhNaUF4TGpjZ015NHdNRElnTXk0ek16SWdNUzQzTXprZ01TNDFPRFlnTXk0ek5TQXpMakExTmlBMUxqY3pNaUEwTGpNNU9DQXpMakk1TXlBeExqZzFOU0EyTGpFMU1TQXlMak01TmlBNExqYzVNU0F5TGpnNU5pQXhMamcxTlM0ek5TQTFMakUwT1M0NU5EZ2dPUzQwT0RndU5UVTJZVE15TGpjd055QXpNaTQzTURjZ01DQXdJREFnT1M0ek1UVXRNaTR5T0Rkak1TNDROakl0TGpjMU9TQTBMalkwTWkweExqa3hOeUEzTGpZek15MDBMalFnTVM0ek5EZ3RNUzR4TWlBekxqUTBPQzB5TGpnNU55QTFMakU1TnkwMUxqazFZVEl3TGpFeE5DQXlNQzR4TVRRZ01DQXdJREFnTWk0eU5TMDFMams1T0dNdU1qRXRNVGN1TlRVeUxqUXlMVE0xTGpFd05DNDJNekl0TlRJdU5qVTNiQzAxTmk0NExqazFNbWd1TURBeFdpSWdabWxzYkQwaUkwSXpRak5DTXlJdlBqeHdZWFJvSUdROUlrMDFOeTQwT0NBeE9TNDBPREpETlRjdU5qUTFJRGt1TWpRZ05EUXVPVGM0TGpjeU55QXlPUzR4T0RjdU5EWTRJREV6TGpNNU55NHlNUzQwTmpNZ09DNHpNRE11TWprNElERTRMalUwTmk0eE16UWdNamd1TnpnNElERXlMamdnTXpjdU15QXlPQzQxT1RFZ016Y3VOVFpqTVRVdU56a3VNalU0SURJNExqY3lOQzAzTGpnek5TQXlPQzQ0T0RrdE1UZ3VNRGM0V2lJZ1ptbHNiRDBpSTBORFF5SXZQanh3WVhSb0lHUTlJazB6TUM0ek1UUWdOeTR4TXpkakxqQXdPUzB1TlRZeExTNDJPQzB4TGpBeU9DMHhMalV6T0MweExqQTBNaTB1T0RVNUxTNHdNVFF0TVM0MU5qSXVORE10TVM0MU56RXVPVGt4TFM0d01TNDFOakl1TmpnZ01TNHdNamdnTVM0MU16Z2dNUzR3TkRJdU9EVTVMakF4TlNBeExqVTJNaTB1TkRNZ01TNDFOeTB1T1RsYUlpQm1hV3hzUFNJak5qWTJJaTgrUEhCaGRHZ2daRDBpVFRZdU5ERTBJREk0TGpnNVlURTFMamMzTnlBeE5TNDNOemNnTUNBd0lERXRNaTR3T1RNdE1pNHhORFpqTFM0NE5UWXRNUzR3TmpNdE1pNDBOVE10TXk0d09UTXRNaTQ1TnpVdE5pNHhNVEpoTVRFdU56WTFJREV4TGpjMk5TQXdJREFnTVMwdU1Ea3pMVE11TXpBM2JESTFMalF6TFRrdU9UYzJZeTR3TkRNdU1UUXlMakU0T0M0MU5UVXVOakEwTGpnMk9DNDBOaTR6TkRZdU9UUTNMak0wSURFdU1EZzJMak16TkV3MkxqUXhNeUF5T0M0NE9EaDJMakF3TWxvaUlHWnBiR3c5SWlORk5rVTJSVFlpTHo0OGNHRjBhQ0J2Y0dGamFYUjVQU0l1TXpNaUlHUTlJazB4TGpRM055QXhOaTR3TWpsakxqSTFMUzQ1TXpFdU56QTJMVEl1TWpVNElERXVOVGN0TXk0Mk9UVXVOalUxTFRFdU1Ea3lJREV1TWpreUxURXVPREkxSURFdU56WXRNaTR6TlRndU5UZzBMUzQyTmpVZ01TNDNOell0TVM0NU16UWdNeTQyTnprdE15NHlPU0F5TGprMU15MHlMakV3TlNBMUxqWTVOaTB6TGpBMUlEY3VOekl6TFRNdU56TmhNemN1TXpVZ016Y3VNelVnTUNBd0lERWdOaTQwT0RVdE1TNDFORGRzTlM0eU5ESWdOQzR6TVRaaE1TNDBPQ0F4TGpRNElEQWdNQ0F3TFRFdU1qRTBMamsyTjB3eExqUTRJREUyTGpBemFDMHVNREF5V2lJZ1ptbHNiRDBpSXprNU9TSXZQanh3WVhSb0lHOXdZV05wZEhrOUlpNDBOQ0lnWkQwaVRURXVPREVnTWpZdU5UTXlZeTR5TURZdU5EazBMalE0TkNBeExqQTFMamcySURFdU5qTmhNVEF1TWpZMklERXdMakkyTmlBd0lEQWdNQ0F5TGpJM09DQXlMalE0Tmt3MkxqVTFNaUEzT0M0eU1tRXhOeTR5TnpJZ01UY3VNamN5SURBZ01DQXhMVE10Tnk0ME1UTk1NUzQ0TVNBeU5pNDFNekphSWlCbWFXeHNQU0lqUlRaRk5rVTJJaTgrUEhCaGRHZ2daRDBpYlRNekxqQTVNaUEwT1M0ME5ERXROaTR6T0RFZ01UVXVNakV4Y3kwMkxqQTNPQzB4TVM0eE5Ua2dOaTR6T0RFdE1UVXVNakZhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEhCaGRHZ2daRDBpYlRJMkxqY3lOU0EyTkM0NE5UZ3RMakE1TVMwdU1UYzFZeTB1TURJMkxTNHdORGt0TWk0Mk16UXROQzQ1TWpNdExqZzJOeTA1TGpNM0lERXVNRFUzTFRJdU56RTNJRE11TlRFNExUUXVOekkxSURjdU15MDFMamswTm13dU1UZzNMUzR3TmpFdE5pNDFNeUF4TlM0MU5USmFiVFl1TWpFeUxURTFMakkyT0dNdE15NDJNakVnTVM0eU1UY3ROUzQ1T1RFZ015NHhOamd0Tnk0d01qSWdOUzQzT1RndE1TNDFNemdnTXk0NU1EZ3VNelUxSURndU1UWTJMamM0T0NBNUxqQTFOR3cyTGpJek5DMHhOQzQ0TlRKYVRUSTRMakE1TXlBMk15NDNNemRzTkM0ME9EUXRNVEF1T0Rkek55NHpOalVnTmk0ek16Y3ROQzQwT0RRZ01UQXVPRGRhSWlCbWFXeHNQU0lqT0VVNFJUaEZJaTgrUEM5blBqeG5JR2xrUFNKQ1JVRk9JajQ4Y21WamRDQjNhV1IwYUQwaU1USWlJR2hsYVdkb2REMGlNVElpSUhKNFBTSTJJaUJtYVd4c1BTSWpORFpDT1RVMUlpOCtQSEJoZEdnZ1pEMGliVGN1TmpnM0lERXVNalkxTFRNdU5UQTBJRGt1TXpaVExqSTVPQ0F6TGprNU9TQTNMalk0TnlBeExqSTJObHB0TFRJdU5qa3hJRGd1TnpnZ01pNDBOakl0Tmk0Mk9URnpOQzQxTXpnZ015NDJOeTB5TGpRMk1pQTJMalk1TVZvaUlHWnBiR3c5SWlObVptWWlMejQ4TDJjK1BHY2dhV1E5SWtKRlFVNHpRMUpXSWo0OGNtVmpkQ0I1UFNJdU5TSWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE55QXhMamMyTkMwekxqVXdOQ0E1TGpNMlV5NHlPVGdnTkM0ME9Ua2dOeTQyT0RjZ01TNDNOalZhSWlCbWFXeHNQU0lqWm1abUlpOCtQSEJoZEdnZ1pEMGlUVGd1TVRNeUlEZ3VNRGM0WXkwdU5EWTJMalkwTFRFdU1qazNJREV1TXpJekxUSXVOamsxSURFdU9Ua3liREl1TVRJMkxUVXVOemMzWXk0d09Ea3VNRGt1TVRrekxqSXdOQzR6TGpNek9DNHpNRE11TXpjMUxqWXlOUzQ0T1RFdU56UTBJREV1TkRnMExqRXhOeTQxT0RNdU1EUWdNUzR5TlRNdExqUTNOU0F4TGprMk0xb2lJR1pwYkd3OUluVnliQ2dqWVNraUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMWGRwWkhSb1BTSXVOU0l2UGp4a1pXWnpQanhzYVc1bFlYSkhjbUZrYVdWdWRDQnBaRDBpWVNJZ2VERTlJall1T1RVaUlIa3hQU0l6TGpnMU15SWdlREk5SWpZdU9UVWlJSGt5UFNJeE1DNDFORFFpSUdkeVlXUnBaVzUwVlc1cGRITTlJblZ6WlhKVGNHRmpaVTl1VlhObElqNDhjM1J2Y0NCemRHOXdMV052Ykc5eVBTSWpPREl3TWpBeUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJdU1UZ3lJaUJ6ZEc5d0xXTnZiRzl5UFNJalJqY3hSVEExSWk4K1BITjBiM0FnYjJabWMyVjBQU0l1TlRFMklpQnpkRzl3TFdOdmJHOXlQU0lqUmpCR05UQTNJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXVOek0wSWlCemRHOXdMV052Ykc5eVBTSWpPRFZEUkRjMUlpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeElpQnpkRzl3TFdOdmJHOXlQU0lqTURJNVJFWkNJaTgrUEM5c2FXNWxZWEpIY21Ga2FXVnVkRDQ4TDJSbFpuTStQQzluUGp4bklHbGtQU0oxY2tKRlFVNGlQanh5WldOMElIZHBaSFJvUFNJeE1pSWdhR1ZwWjJoMFBTSXhNaUlnY25nOUlqWWlJR1pwYkd3OUlpTTNSalUxTXpNaUx6NDhjR0YwYUNCa1BTSnROeTQyT0RjZ01TNHlOalV0TXk0MU1EUWdPUzR6TmxNdU1qazRJRE11T1RrNUlEY3VOamczSURFdU1qWTJXbTB0TWk0Mk9URWdPQzQzT0NBeUxqUTJNaTAyTGpZNU1YTTBMalV6T0NBekxqWTNMVEl1TkRZeUlEWXVOamt4V2lJZ1ptbHNiRDBpSTJabVppSXZQand2Wno0OFp5QnBaRDBpUWtWQlRrVlVTQ0krUEhKbFkzUWdkMmxrZEdnOUlqRXlJaUJvWldsbmFIUTlJakV5SWlCeWVEMGlOaUlnWm1sc2JEMGlJelEyUWprMU5TSXZQanh3WVhSb0lHUTlJbTAzTGpZNE5DQXhMakkyTlMwekxqVXdOU0E1TGpNMll5NHdNRE1nTUMwekxqZzROQzAyTGpZeU5TQXpMalV3TlMwNUxqTTJXaUlnWm1sc2JEMGlJMlptWmlJdlBqeHdZWFJvSUdROUlrMDRMamsxTWlBMkxqazRObUV1TURZekxqQTJNeUF3SURBZ01TMHVNREl5TGpBd00yTXRMamN4TGpFekxURXVOREkwTGpJMU5TMHlMakV6TkM0ek9ERXRMakk0TVM0d05USXRMalUyTlM0eE1ETXRMamcwTmk0eE5USmhMakF6Tmk0d016WWdNQ0F3SURFdExqQXlOaUF3YkRJdU1UUXROUzQyTWpVdU1EQTBMUzR3TUROakxqSTVOeUF4TGpjd01pNDFPU0F6TGpNNU5DNDRPRFFnTlM0d09USmFiUzB1TVRnM0xqUTNPR010TVM0eU5qWXVPRFU1TFRJdU5UTXhJREV1TnpJeExUTXVPQ0F5TGpVNGJDNDNPREV0TWk0d05UUmpMakF3Tnk0d01EUXVNREV6SURBZ0xqQXlNeUF3SUM0M05Ua3RMakV6TWlBeExqVXhOQzB1TWpZNElESXVNamN0TGpSc0xqWTVOeTB1TVRJMkxqQXpMUzR3TURaakxTNHdNRFF1TURBeklEQWdMakF3TmlBd0lDNHdNRFphSWlCbWFXeHNQU0lqTURBd0lpOCtQQzluUGp4bklHbGtQU0oxY2tKRlFVNUZWRWdpUGp4eVpXTjBJSGRwWkhSb1BTSXhNaUlnYUdWcFoyaDBQU0l4TWlJZ2NuZzlJallpSUdacGJHdzlJaU0zUmpVMU16TWlMejQ4Y0dGMGFDQmtQU0p0Tnk0Mk9EUWdNUzR5TmpVdE15NDFNRFVnT1M0ek5tTXVNREF6SURBdE15NDRPRFF0Tmk0Mk1qVWdNeTQxTURVdE9TNHpObG9pSUdacGJHdzlJaU5tWm1ZaUx6NDhjR0YwYUNCa1BTSk5PQzQ1TlRJZ05pNDVPRFpoTGpBMk15NHdOak1nTUNBd0lERXRMakF5TWk0d01ETmpMUzQzTVM0eE15MHhMalF5TkM0eU5UVXRNaTR4TXpRdU16Z3hMUzR5T0RFdU1EVXlMUzQxTmpVdU1UQXpMUzQ0TkRZdU1UVXlZUzR3TXpZdU1ETTJJREFnTUNBeExTNHdNallnTUd3eUxqRTBMVFV1TmpJMUxqQXdOQzB1TURBell5NHlPVGNnTVM0M01ESXVOVGtnTXk0ek9UUXVPRGcwSURVdU1Ea3lXbTB0TGpFNE55NDBOemhqTFRFdU1qWTJMamcxT1MweUxqVXpNU0F4TGpjeU1TMHpMamdnTWk0MU9Hd3VOemd4TFRJdU1EVTBZeTR3TURjdU1EQTBMakF4TXlBd0lDNHdNak1nTUNBdU56VTVMUzR4TXpJZ01TNDFNVFF0TGpJMk9DQXlMakkzTFM0MGJDNDJPVGN0TGpFeU5pNHdNeTB1TURBMll5MHVNREEwTGpBd015QXdJQzR3TURZZ01DQXVNREEyV2lJZ1ptbHNiRDBpSXpBd01DSXZQand2Wno0OFp5QnBaRDBpYkdWaFpsSnZkeUkrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYkdWaFppSWdlRDBpTUNJZ2VUMGlNQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkweE1pSWdlVDBpTFRjaUx6NDhkWE5sSUhoc2FXNXJPbWh5WldZOUlpTnNaV0ZtSWlCNFBTSXRNalFpSUhrOUlpMHhOQ0l2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJ4bFlXWWlJSGc5SWkwek5pSWdlVDBpTFRJeElpOCtQQzluUGp3dlpHVm1jejQ4Y21WamRDQjNhV1IwYUQwaU1qVTFJaUJvWldsbmFIUTlJak0xTUNJZ2NuZzlJakV3SWlCbWFXeHNQU0lqTWpVek16STJJaTgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqYzJsc2J5SWdlRDBpT1RraUlIazlJalUxSWk4K1BHY2dhV1E5SW1Gc2JGQnNiM1FpSUdOc2FYQXRjR0YwYUQwaWRYSnNLQ05pYjNKa1pYSk5ZWE5yS1NJK1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TmpraUlIazlJaTB4TmpRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJMk9TSWdlVDBpTFRFMk5DSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU5sYlhCMGVWQnNiM1FpSUhnOUlqQWlJSGs5SWkweE1qUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSXhNemdpSUhrOUlpMHhNalFpSUM4K1BIVnpaU0I0YkdsdWF6cG9jbVZtUFNJalpXMXdkSGxRYkc5MElpQjRQU0l0TVRNNElpQjVQU0l0TVRJMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaUxUWTVJaUI1UFNJdE9EUWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSTJPU0lnZVQwaUxUZzBJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlMVEV6T0NJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTUNJZ2VUMGlMVFEwSWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyVnRjSFI1VUd4dmRDSWdlRDBpTVRNNElpQjVQU0l0TkRRaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU5qa2lJSGs5SWkwMElpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM05wYkc4aUlIZzlJalEzSWlCNVBTSTFOU0lnZEhKaGJuTm1iM0p0UFNKelkyRnNaU2d4TGpjcElpOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE1UTTRJaUI1UFNJek5pSWdMejQ4ZFhObElIaHNhVzVyT21oeVpXWTlJaU53WVhKMGFXRnNUR1ZoWmxCc2IzUWlJSGc5SWpFek9DSWdlVDBpTXpZaUlDOCtQSFZ6WlNCNGJHbHVhenBvY21WbVBTSWpaVzF3ZEhsUWJHOTBJaUI0UFNJdE5qa2lJSGs5SWpjMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMloxYkd4TVpXRm1VR3h2ZENJZ2VEMGlOamtpSUhrOUlqYzJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlMVEV6T0NJZ2VUMGlNVEUySWlBdlBqeDFjMlVnZUd4cGJtczZhSEpsWmowaUkyWjFiR3hNWldGbVVHeHZkQ0lnZUQwaU1DSWdlVDBpTVRFMklpQXZQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJMlZ0Y0hSNVVHeHZkQ0lnZUQwaU1UTTRJaUI1UFNJeE1UWWlJQzgrUEhWelpTQjRiR2x1YXpwb2NtVm1QU0lqWlcxd2RIbFFiRzkwSWlCNFBTSTJPU0lnZVQwaU1UVTJJaUF2UGp4MWMyVWdlR3hwYm1zNmFISmxaajBpSTJWdGNIUjVVR3h2ZENJZ2VEMGlMVFk1SWlCNVBTSXhOVFlpSUM4K1BDOW5Qanh5WldOMElIZzlJakFpSUhrOUlqQWlJSGRwWkhSb1BTSXlOVFVpSUdobGFXZG9kRDBpTWpBaUlISjRQU0kxSWlCbWFXeHNQU0lqTWpReU5ESTBJaTgrUEhSbGVIUWdlRDBpTVRBaUlIazlJakUwTGpVaUlHWnZiblF0YzJsNlpUMGlNVElpSUdacGJHdzlJbGRvYVhSbElpQjBaWGgwTFdGdVkyaHZjajBpYzNSaGNuUWlJR1p2Ym5RdFptRnRhV3g1UFNKbWRYUjFjbUVpUG5WeVFrVkJUa1ZVU0NCRVpYQnZjMmwwUEM5MFpYaDBQangxYzJVZ2VHeHBibXM2YUhKbFpqMGlJM1Z5UWtWQlRrVlVTQ0lnZUQwaU1qUXdJaUI1UFNJMElpQXZQanh5WldOMElIZzlJakFpSUhrOUlqTXpNQ0lnZDJsa2RHZzlJakkxTlNJZ2FHVnBaMmgwUFNJeU1DSWdjbmc5SWpVaUlHWnBiR3c5SWlNeU5ESTBNalFpTHo0OGRHVjRkQ0I0UFNJeE1qY2lJSGs5SWpNME15SWdabTl1ZEMxemFYcGxQU0l4TUNJZ1ptbHNiRDBpVjJocGRHVWlJSFJsZUhRdFlXNWphRzl5UFNKdGFXUmtiR1VpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBqeDBjM0JoYmo0OFlXNXBiV0YwWlNCaGRIUnlhV0oxZEdWT1lXMWxQU0o0SWlCbWNtOXRQU0l6TnpVaUlIUnZQU0kxTUNJZ1pIVnlQU0l4TUhNaUlISmxjR1ZoZEVOdmRXNTBQU0pwYm1SbFptbHVhWFJsSWlBdlBqQjRNV0psWVROalkyUXlNbVkwWldKa00yUXpOMlEzTXpGaVlUTXhaV1ZqWVRrMU56RXpOekUyWkR3dmRITndZVzQrUEM5MFpYaDBQangwWlhoMElIZzlJakV5TnlJZ2VUMGlNelF6SWlCbWIyNTBMWE5wZW1VOUlqRXdJaUJtYVd4c1BTSlhhR2wwWlNJZ2RHVjRkQzFoYm1Ob2IzSTlJbTFwWkdSc1pTSWdabTl1ZEMxbVlXMXBiSGs5SW1aMWRIVnlZU0krUEhSemNHRnVQanhoYm1sdFlYUmxJR0YwZEhKcFluVjBaVTVoYldVOUluZ2lJR1p5YjIwOUlqVXdJaUIwYnowaUxUSTNOU0lnWkhWeVBTSXhNSE1pSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUF2UGpCNE1XSmxZVE5qWTJReU1tWTBaV0prTTJRek4yUTNNekZpWVRNeFpXVmpZVGsxTnpFek56RTJaRHd2ZEhOd1lXNCtQQzkwWlhoMFBqeDBaWGgwSUhnOUlqSXpOU0lnZVQwaU1UUXVOU0lnWm05dWRDMXphWHBsUFNJeE1pSWdabWxzYkQwaVYyaHBkR1VpSUhSbGVIUXRZVzVqYUc5eVBTSmxibVFpSUdadmJuUXRabUZ0YVd4NVBTSm1kWFIxY21FaVBsTjBaVzA2SUMweE5qWTRQQzkwWlhoMFBqd3ZjM1puUGc9PSJ9 \ No newline at end of file From 81c527d1faeef872bf0867d01230b01e71652dcc Mon Sep 17 00:00:00 2001 From: brendan Date: Tue, 26 Sep 2023 13:49:53 -0400 Subject: [PATCH 92/96] add migrated BDV counter --- protocol/abi/Beanstalk.json | 19 +++++++++++++++++++ protocol/contracts/beanstalk/AppStorage.sol | 4 ++++ .../beanstalk/silo/MigrationFacet.sol | 8 ++++++++ .../libraries/Silo/LibLegacyTokenSilo.sol | 13 +++++++++++++ protocol/test/Stem.test.js | 12 +++++++++++- 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/protocol/abi/Beanstalk.json b/protocol/abi/Beanstalk.json index d9f419d093..611c91aea5 100644 --- a/protocol/abi/Beanstalk.json +++ b/protocol/abi/Beanstalk.json @@ -4420,6 +4420,25 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "totalMigratedBdv", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "anonymous": false, "inputs": [ diff --git a/protocol/contracts/beanstalk/AppStorage.sol b/protocol/contracts/beanstalk/AppStorage.sol index b3d3f33698..a6a54ffe7b 100644 --- a/protocol/contracts/beanstalk/AppStorage.sol +++ b/protocol/contracts/beanstalk/AppStorage.sol @@ -487,6 +487,7 @@ contract Storage { * @param ownerCandidate Stores a candidate address to transfer ownership to. The owner must claim the ownership transfer. * @param wellOracleSnapshots A mapping from Well Oracle address to the Well Oracle Snapshot. * @param beanEthPrice Stores the beanEthPrice during the sunrise() function. Returns 1 otherwise. + * @param migratedBdvs Stores the total migrated BDV since the implementation of the migrated BDV counter. See {LibLegacyTokenSilo.incrementMigratedBdv} for more info. */ struct AppStorage { uint8 deprecated_index; @@ -547,4 +548,7 @@ struct AppStorage { // Well mapping(address => bytes) wellOracleSnapshots; uint256 beanEthPrice; + + // Silo V3 BDV Migration + mapping(address => uint256) migratedBdvs; } \ No newline at end of file diff --git a/protocol/contracts/beanstalk/silo/MigrationFacet.sol b/protocol/contracts/beanstalk/silo/MigrationFacet.sol index 130d49e7c3..e5a34ad660 100644 --- a/protocol/contracts/beanstalk/silo/MigrationFacet.sol +++ b/protocol/contracts/beanstalk/silo/MigrationFacet.sol @@ -109,4 +109,12 @@ contract MigrationFacet is ReentrancyGuard { ); } + /** + * @dev Returns the total Migrated BDV since the implementation of the Migration BDV counter. + */ + function totalMigratedBdv(address token) external view returns (uint256) { + AppStorage storage s = LibAppStorage.diamondStorage(); + return s.migratedBdvs[token]; + } + } \ No newline at end of file diff --git a/protocol/contracts/libraries/Silo/LibLegacyTokenSilo.sol b/protocol/contracts/libraries/Silo/LibLegacyTokenSilo.sol index 4d1d38adf7..96262b4e49 100644 --- a/protocol/contracts/libraries/Silo/LibLegacyTokenSilo.sol +++ b/protocol/contracts/libraries/Silo/LibLegacyTokenSilo.sol @@ -350,6 +350,7 @@ library LibLegacyTokenSilo { // Include Deposit in the total Deposited BDV. LibTokenSilo.incrementTotalDepositedBdv(perTokenData.token, crateBDV); + incrementMigratedBdv(perTokenData.token, crateBDV); // add to running total of seeds migrateData.totalSeeds = migrateData.totalSeeds.add(crateBDV.mul(getSeedsPerToken(address(perTokenData.token))).toUint128()); @@ -558,4 +559,16 @@ library LibLegacyTokenSilo { delete s.a[account].withdrawals[token][season]; return amount; } + + /** + * @dev Increments the Migrated BDV counter for a given `token` by `bdv`. + * The `depositedBdv` variable in `Storage.AssetSilo` does not include unmigrated BDV and thus is not accurrate. + * In a potential future update, it will be necessary for `depositedBdv` to include unmigrated BDV. + * By summating the `migratedBdv` counter, we can properly account for unmigrated BDV through + * a 2 step asynchronous upgrade process where adding this counter is the first step. + */ + function incrementMigratedBdv(address token, uint256 bdv) private { + AppStorage storage s = LibAppStorage.diamondStorage(); + s.migratedBdvs[token] = s.migratedBdvs[token].add(bdv); + } } diff --git a/protocol/test/Stem.test.js b/protocol/test/Stem.test.js index 53789aead7..2bbbdcd830 100644 --- a/protocol/test/Stem.test.js +++ b/protocol/test/Stem.test.js @@ -16,6 +16,7 @@ const { setEthUsdPrice, setEthUsdcPrice } = require('../utils/oracle.js'); const { impersonateEthUsdChainlinkAggregator, impersonateEthUsdcUniswap, impersonateBean, impersonateWeth } = require('../scripts/impersonate.js'); const { bipMigrateUnripeBean3CrvToBeanEth } = require('../scripts/bips.js'); const { finishBeanEthMigration } = require('../scripts/beanEthMigration.js'); +const { toBN } = require('../utils/helpers.js'); require('dotenv').config(); let user,user2,owner; @@ -159,15 +160,20 @@ describe('Silo V3: Grown Stalk Per Bdv deployment', function () { const seasons = [[6074],[6061],[6137]]; const amounts = []; - for(let i=0; i Date: Thu, 28 Sep 2023 08:27:26 -0400 Subject: [PATCH 93/96] add UsdOracle contract --- .../contracts/ecosystem/oracles/UsdOracle.sol | 23 +++++++++++++++++++ protocol/scripts/bips.js | 12 ++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 protocol/contracts/ecosystem/oracles/UsdOracle.sol diff --git a/protocol/contracts/ecosystem/oracles/UsdOracle.sol b/protocol/contracts/ecosystem/oracles/UsdOracle.sol new file mode 100644 index 0000000000..49c9ee1d6d --- /dev/null +++ b/protocol/contracts/ecosystem/oracles/UsdOracle.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity =0.7.6; +pragma experimental ABIEncoderV2; + +import {LibUsdOracle, LibEthUsdOracle} from "contracts/libraries/Oracle/LibUsdOracle.sol"; + +/** + * @title UsdOracle + * @author Publius + * @notice Holds functions to query USD prices of tokens. + */ +contract UsdOracle { + + function getUsdPrice(address token) external view returns (uint256) { + return LibUsdOracle.getUsdPrice(token); + } + + function getEthUsdPrice() external view returns (uint256) { + return LibEthUsdOracle.getEthUsdPrice(); + } + +} diff --git a/protocol/scripts/bips.js b/protocol/scripts/bips.js index b9a2bb19cd..feb9ddaf29 100644 --- a/protocol/scripts/bips.js +++ b/protocol/scripts/bips.js @@ -1,5 +1,6 @@ const { BEANSTALK } = require("../test/utils/constants"); -const { getBeanstalk, impersonateBeanstalkOwner, mintEth } = require("../utils"); +const { getBeanstalk, impersonateBeanstalkOwner, mintEth, impersonateSigner } = require("../utils"); +const { deployContract } = require("./contracts"); const { upgradeWithNewFacets } = require("./diamond"); const { impersonatePipeline, deployPipeline } = require("./pipeline"); @@ -144,7 +145,7 @@ async function bip34(mock = true, account = undefined) { verify: false }); } -async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefined, verbose = true) { +async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefined, verbose = true, oracleAccount = undefined) { if (account == undefined) { account = await impersonateBeanstalkOwner(); await mintEth(account.address); @@ -171,6 +172,13 @@ async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefine verify: false }); + + if (oracleAccount == undefined) { + oracleAccount = await impersonateSigner('0x30a1976d5d087ef0BA0B4CDe87cc224B74a9c752', true); // Oracle deployer + await mintEth(oracleAccount.address); + } + await deployContract('UsdOracle', oracleAccount, true) + } exports.bip29 = bip29 From fa06ae189cd32c176083d1ac4b90a63d722c1b01 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 11 Oct 2023 19:17:59 +0100 Subject: [PATCH 94/96] revert projects/ui/src/graph/graphql.schema.json --- projects/ui/src/graph/graphql.schema.json | 3038 +-------------------- 1 file changed, 4 insertions(+), 3034 deletions(-) diff --git a/projects/ui/src/graph/graphql.schema.json b/projects/ui/src/graph/graphql.schema.json index 5a41d47910..0cbf867354 100644 --- a/projects/ui/src/graph/graphql.schema.json +++ b/projects/ui/src/graph/graphql.schema.json @@ -16572,22 +16572,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "overall", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "pool", "description": null, @@ -17452,70 +17436,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "overall", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "overall_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "overall_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "overall_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "pool", "description": null, @@ -18897,12 +18817,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "overall", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "pool", "description": null, @@ -105220,176 +105134,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "wellOracle", - "description": null, - "args": [ - { - "name": "block", - "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", - "type": { - "kind": "INPUT_OBJECT", - "name": "Block_height", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subgraphError", - "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_SubgraphErrorPolicy_", - "ofType": null - } - }, - "defaultValue": "deny", - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "wellOracles", - "description": null, - "args": [ - { - "name": "block", - "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", - "type": { - "kind": "INPUT_OBJECT", - "name": "Block_height", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": "100", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "WellOracle_orderBy", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orderDirection", - "description": null, - "type": { - "kind": "ENUM", - "name": "OrderDirection", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": "0", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subgraphError", - "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_SubgraphErrorPolicy_", - "ofType": null - } - }, - "defaultValue": "deny", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "where", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "whitelistToken", "description": null, @@ -125507,11 +125251,6 @@ "name": "StalkChange", "ofType": null }, - { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - }, { "kind": "OBJECT", "name": "WhitelistToken", @@ -131078,41 +130817,9 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "fourPointFiveSeedBeanAPY", - "description": "Bean APY for 4.5 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY", - "description": "Stalk APY for 4.5 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "fourSeedBeanAPY", - "description": "Bean APY for 4 seeds per BDV", + "description": "Bean APY for four seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -131128,7 +130835,7 @@ }, { "name": "fourSeedStalkAPY", - "description": "Stalk APY for 4 seeds per BDV", + "description": "Stalk APY for four seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -131174,73 +130881,9 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "threePointTwoFiveSeedBeanAPY", - "description": "Bean APY for 3.25 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY", - "description": "Stalk APY for 3.25 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY", - "description": "Bean APY for 3 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY", - "description": "Stalk APY for 3 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "twoSeedBeanAPY", - "description": "Bean APY for 2 seeds per BDV", + "description": "Bean APY for two seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -131256,7 +130899,7 @@ }, { "name": "twoSeedStalkAPY", - "description": "Stalk APY for 2 seeds per BDV", + "description": "Stalk APY for two seeds per BDV", "args": [], "type": { "kind": "NON_NULL", @@ -131285,22 +130928,6 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY", - "description": "Bean APY for 0 seeds per BDV", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, @@ -131678,230 +131305,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "fourPointFiveSeedBeanAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedBeanAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "fourSeedBeanAPY", "description": null, @@ -132366,454 +131769,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "threePointTwoFiveSeedBeanAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedBeanAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "twoSeedBeanAPY", "description": null, @@ -133149,118 +132104,6 @@ "defaultValue": null, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigDecimal", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null } ], "interfaces": null, @@ -133293,18 +132136,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "fourPointFiveSeedBeanAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fourPointFiveSeedStalkAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "fourSeedBeanAPY", "description": null, @@ -133329,30 +132160,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "threePointTwoFiveSeedBeanAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threePointTwoFiveSeedStalkAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedBeanAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threeSeedStalkAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "twoSeedBeanAPY", "description": null, @@ -133370,12 +132177,6 @@ "description": null, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "zeroSeedBeanAPY", - "description": null, - "isDeprecated": false, - "deprecationReason": null } ], "possibleTypes": null @@ -148307,176 +147108,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "wellOracle", - "description": null, - "args": [ - { - "name": "block", - "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", - "type": { - "kind": "INPUT_OBJECT", - "name": "Block_height", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subgraphError", - "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_SubgraphErrorPolicy_", - "ofType": null - } - }, - "defaultValue": "deny", - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "wellOracles", - "description": null, - "args": [ - { - "name": "block", - "description": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", - "type": { - "kind": "INPUT_OBJECT", - "name": "Block_height", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": "100", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "WellOracle_orderBy", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orderDirection", - "description": null, - "type": { - "kind": "ENUM", - "name": "OrderDirection", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": "0", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subgraphError", - "description": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_SubgraphErrorPolicy_", - "ofType": null - } - }, - "defaultValue": "deny", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "where", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "WellOracle", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "whitelistToken", "description": null, @@ -150336,1667 +148967,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "OBJECT", - "name": "WellOracle", - "description": null, - "fields": [ - { - "name": "blockNumber", - "description": " Block number of this event ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": " Timestamp of this event ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves", - "description": " Time weighted cumulative reserves ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB", - "description": " DeltaB for season", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash", - "description": " Transaction hash of the transaction that emitted this event ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "wellOracle-{ Transaction hash }-{ Log index }", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex", - "description": " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol", - "description": " The protocol this transaction belongs to ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Beanstalk", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season", - "description": " Season of oracle ", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "SiloEvent", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "description": null, - "fields": null, - "inputFields": [ - { - "name": "_change_block", - "description": "Filter for the block changed event.", - "type": { - "kind": "INPUT_OBJECT", - "name": "BlockChangedFilter", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "and", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "blockNumber_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_not_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Bytes", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "BigInt", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_contains_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_ends_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_ends_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_contains_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_ends_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_ends_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_starts_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_not_starts_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_starts_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash_starts_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "or", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "WellOracle_filter", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "Beanstalk_filter", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_contains_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_ends_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_ends_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_contains", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_contains_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_ends_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_ends_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_starts_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_not_starts_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_starts_with", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol_starts_with_nocase", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_gt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_gte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_lt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_lte", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_not", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season_not_in", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "WellOracle_orderBy", - "description": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "blockNumber", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cumulativeReserves", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deltaB", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndex", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__id", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__lastSeason", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__lastUpgrade", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__methodologyVersion", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__name", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__schemaVersion", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__slug", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol__subgraphVersion", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, { "kind": "OBJECT", "name": "WhitelistToken", From 70b4d7af84c87c0acc7524c566651f898eb7a06b Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 11 Oct 2023 19:21:48 +0100 Subject: [PATCH 95/96] remove goerli private key --- protocol/hardhat.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/protocol/hardhat.config.js b/protocol/hardhat.config.js index 25c47db484..5aa013e896 100644 --- a/protocol/hardhat.config.js +++ b/protocol/hardhat.config.js @@ -263,7 +263,6 @@ module.exports = { goerli: { chainId: 5, url: process.env.GOERLI_RPC || "", - accounts: [process.env.GOERLI_PRIVATE_KEY], timeout: 100000 } }, From 2dfa20195cdfea4d11b2f417b2aa1b77daf5fcb3 Mon Sep 17 00:00:00 2001 From: brendan Date: Wed, 11 Oct 2023 22:10:40 +0100 Subject: [PATCH 96/96] update BIP-38 deploy script --- protocol/scripts/bips.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/protocol/scripts/bips.js b/protocol/scripts/bips.js index feb9ddaf29..7b6b52283f 100644 --- a/protocol/scripts/bips.js +++ b/protocol/scripts/bips.js @@ -154,11 +154,13 @@ async function bipMigrateUnripeBean3CrvToBeanEth(mock = true, account = undefine await upgradeWithNewFacets({ diamondAddress: BEANSTALK, facetNames: [ - "UnripeFacet", - "FertilizerFacet", "BDVFacet", "ConvertFacet", - "ConvertGettersFacet" + "ConvertGettersFacet", + "FertilizerFacet", + "MetadataFacet", + "MigrationFacet", + "UnripeFacet", ], initFacetName: "InitMigrateUnripeBean3CrvToBeanEth", selectorsToRemove: [